--- a/widget/src/gtk2/nsClipboard.cpp
+++ b/widget/src/gtk2/nsClipboard.cpp
@@ -41,45 +41,45 @@
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsXPIDLString.h"
#include "nsPrimitiveHelpers.h"
#include "nsICharsetConverterManager.h"
#include "nsIServiceManager.h"
#include "nsImageToPixbuf.h"
#include "nsStringStream.h"
+#include "nsIObserverService.h"
#include "imgIContainer.h"
#include <gtk/gtk.h>
// For manipulation of the X event queue
#include <X11/Xlib.h>
#include <gdk/gdkx.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef POLL_WITH_XCONNECTIONNUMBER
#include <poll.h>
#endif
-// Callback when someone asks us for the selection
+// Callback when someone asks us for the data
void
-invisible_selection_get_cb (GtkWidget *aWidget,
- GtkSelectionData *aSelectionData,
- guint aTime,
- guint aInfo,
- nsClipboard *aClipboard);
+clipboard_get_cb(GtkClipboard *aGtkClipboard,
+ GtkSelectionData *aSelectionData,
+ guint info,
+ gpointer user_data);
-gboolean
-selection_clear_event_cb (GtkWidget *aWidget,
- GdkEventSelection *aEvent,
- nsClipboard *aClipboard);
-
+// Callback when someone asks us to clear a clipboard
+void
+clipboard_clear_cb(GtkClipboard *aGtkClipboard,
+ gpointer user_data);
+
static void
ConvertHTMLtoUCS2 (guchar *data,
PRInt32 dataLength,
PRUnichar **unicodeData,
PRInt32 &outUnicodeLen);
static void
GetHTMLCharset (guchar * data, PRInt32 dataLength, nsCString& str);
@@ -116,43 +116,56 @@ clipboard_contents_received(GtkClipboard
gpointer data);
static void
clipboard_text_received(GtkClipboard *clipboard,
const gchar *text,
gpointer data);
nsClipboard::nsClipboard()
-{
- mWidget = nsnull;
+{
}
nsClipboard::~nsClipboard()
{
- if (mWidget)
- gtk_widget_destroy(mWidget);
}
NS_IMPL_ISUPPORTS1(nsClipboard, nsIClipboard)
nsresult
nsClipboard::Init(void)
-{
- mWidget = gtk_invisible_new();
- if (!mWidget)
- return NS_ERROR_FAILURE;
+{
+ nsresult rv;
+ nsCOMPtr<nsIObserverService> os
+ (do_GetService("@mozilla.org/observer-service;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ os->AddObserver(this, "quit-application", PR_FALSE);
+
+ return NS_OK;
+}
- g_signal_connect(G_OBJECT(mWidget), "selection_get",
- G_CALLBACK(invisible_selection_get_cb), this);
+NS_IMETHODIMP
+nsClipboard::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
+{
+ if (strcmp(aTopic, "quit-application") == 0) {
+ // application is going to quit, save clipboard content
+ Store();
+ }
+ return NS_OK;
+}
- g_signal_connect(G_OBJECT(mWidget), "selection_clear_event",
- G_CALLBACK(selection_clear_event_cb), this);
-
- // XXX make sure to set up the selection_clear event
-
+nsresult
+nsClipboard::Store(void)
+{
+ // Ask the clipboard manager to store the current clipboard content
+ if (mGlobalTransferable) {
+ GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_store(clipboard);
+ }
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::SetData(nsITransferable *aTransferable,
nsIClipboardOwner *aOwner, PRInt32 aWhichClipboard)
{
// See if we can short cut
@@ -171,93 +184,101 @@ nsClipboard::SetData(nsITransferable *aT
NS_ENSURE_SUCCESS(rv, rv);
}
rv = mPrivacyHandler->PrepareDataForClipboard(aTransferable);
NS_ENSURE_SUCCESS(rv, rv);
// Clear out the clipboard in order to set the new data
EmptyClipboard(aWhichClipboard);
- if (aWhichClipboard == kSelectionClipboard) {
- mSelectionOwner = aOwner;
- mSelectionTransferable = aTransferable;
- }
- else {
- mGlobalOwner = aOwner;
- mGlobalTransferable = aTransferable;
- }
-
- // Which selection are we about to claim, CLIPBOARD or PRIMARY?
- GdkAtom selectionAtom = GetSelectionAtom(aWhichClipboard);
-
- // Make ourselves the owner. If we fail to, return.
- if (!gtk_selection_owner_set(mWidget, selectionAtom, GDK_CURRENT_TIME))
- return NS_ERROR_FAILURE;
-
- // Clear the old selection target list.
- gtk_selection_clear_targets(mWidget, selectionAtom);
+ // List of suported targets
+ GtkTargetList *list = gtk_target_list_new(NULL, 0);
// Get the types of supported flavors
nsCOMPtr<nsISupportsArray> flavors;
rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavors));
if (!flavors || NS_FAILED(rv))
return NS_ERROR_FAILURE;
// Add all the flavors to this widget's supported type.
- gint nImageTargets = 0;
+ PRBool imagesAdded = PR_FALSE;
PRUint32 count;
flavors->Count(&count);
for (PRUint32 i=0; i < count; i++) {
nsCOMPtr<nsISupports> tastesLike;
flavors->GetElementAt(i, getter_AddRefs(tastesLike));
nsCOMPtr<nsISupportsCString> flavor = do_QueryInterface(tastesLike);
if (flavor) {
nsXPIDLCString flavorStr;
flavor->ToString(getter_Copies(flavorStr));
// special case text/unicode since we can handle all of
// the string types
if (!strcmp(flavorStr, kUnicodeMime)) {
- AddTarget(gdk_atom_intern("UTF8_STRING", FALSE),
- selectionAtom);
- AddTarget(gdk_atom_intern("COMPOUND_TEXT", FALSE),
- selectionAtom);
- AddTarget(gdk_atom_intern("TEXT", FALSE), selectionAtom);
- AddTarget(GDK_SELECTION_TYPE_STRING, selectionAtom);
- // next loop iteration
+ gtk_target_list_add(list, gdk_atom_intern("UTF8_STRING", FALSE), 0, 0);
+ gtk_target_list_add(list, gdk_atom_intern("COMPOUND_TEXT", FALSE), 0, 0);
+ gtk_target_list_add(list, gdk_atom_intern("TEXT", FALSE), 0, 0);
+ gtk_target_list_add(list, GDK_SELECTION_TYPE_STRING, 0, 0);
continue;
}
if (flavorStr.EqualsLiteral(kNativeImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) ||
flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kGIFImageMime)) {
// don't bother adding image targets twice
- if (!nImageTargets) {
+ if (!imagesAdded) {
// accept any writable image type
- GtkTargetList *list = gtk_target_list_new(NULL, 0);
gtk_target_list_add_image_targets(list, 0, TRUE);
- GtkTargetEntry *targets = gtk_target_table_new_from_list(list, &nImageTargets);
- gtk_selection_add_targets(mWidget, selectionAtom, targets, nImageTargets);
- gtk_target_table_free(targets, nImageTargets);
- gtk_target_list_unref(list);
+ imagesAdded = PR_TRUE;
}
- // next loop iteration
continue;
}
// Add this to our list of valid targets
GdkAtom atom = gdk_atom_intern(flavorStr, FALSE);
- AddTarget(atom, selectionAtom);
+ gtk_target_list_add(list, atom, 0, 0);
}
}
+
+ // Get GTK clipboard (CLIPBOARD or PRIMARY)
+ GtkClipboard *gtkClipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
+
+ gint numTargets;
+ GtkTargetEntry *gtkTargets = gtk_target_table_new_from_list(list, &numTargets);
+
+ // Set getcallback and request to store data after an application exit
+ if (gtk_clipboard_set_with_data(gtkClipboard, gtkTargets, numTargets,
+ clipboard_get_cb, clipboard_clear_cb, this))
+ {
+ // We managed to set-up the clipboard so update internal state
+ // We have to set it now because gtk_clipboard_set_with_data() calls clipboard_clear_cb()
+ // which reset our internal state
+ if (aWhichClipboard == kSelectionClipboard) {
+ mSelectionOwner = aOwner;
+ mSelectionTransferable = aTransferable;
+ }
+ else {
+ mGlobalOwner = aOwner;
+ mGlobalTransferable = aTransferable;
+ gtk_clipboard_set_can_store(gtkClipboard, gtkTargets, numTargets);
+ }
- return NS_OK;
+ rv = NS_OK;
+ }
+ else {
+ rv = NS_ERROR_FAILURE;
+ }
+
+ gtk_target_table_free(gtkTargets, numTargets);
+ gtk_target_list_unref(list);
+
+ return rv;
}
NS_IMETHODIMP
nsClipboard::GetData(nsITransferable *aTransferable, PRInt32 aWhichClipboard)
{
if (!aTransferable)
return NS_ERROR_FAILURE;
@@ -484,25 +505,18 @@ nsClipboard::GetTransferable(PRInt32 aWh
retval = mSelectionTransferable.get();
else
retval = mGlobalTransferable.get();
return retval;
}
void
-nsClipboard::AddTarget(GdkAtom aName, GdkAtom aClipboard)
-{
- gtk_selection_add_target(mWidget, aClipboard, aName, 0);
-}
-
-void
-nsClipboard::SelectionGetEvent (GtkWidget *aWidget,
- GtkSelectionData *aSelectionData,
- guint aTime)
+nsClipboard::SelectionGetEvent(GtkClipboard *aClipboard,
+ GtkSelectionData *aSelectionData)
{
// Someone has asked us to hand them something. The first thing
// that we want to do is see if that something includes text. If
// it does, try to give it text/unicode after converting it to
// utf-8.
PRInt32 whichClipboard;
@@ -510,17 +524,25 @@ nsClipboard::SelectionGetEvent (GtkWidge
if (aSelectionData->selection == GDK_SELECTION_PRIMARY)
whichClipboard = kSelectionClipboard;
else if (aSelectionData->selection == GDK_SELECTION_CLIPBOARD)
whichClipboard = kGlobalClipboard;
else
return; // THAT AIN'T NO CLIPBOARD I EVER HEARD OF
nsCOMPtr<nsITransferable> trans = GetTransferable(whichClipboard);
-
+ if (!trans) {
+ // We have nothing to serve
+#ifdef DEBUG_CLIPBOARD
+ printf("nsClipboard::SelectionGetEvent() - %s clipboard is empty!\n",
+ whichClipboard == kSelectionClipboard ? "Selection" : "Global");
+#endif
+ return;
+ }
+
nsresult rv;
nsCOMPtr<nsISupports> item;
PRUint32 len;
// Check to see if the selection data includes any of the string
// types that we support.
if (aSelectionData->target == gdk_atom_intern ("STRING", FALSE) ||
aSelectionData->target == gdk_atom_intern ("TEXT", FALSE) ||
@@ -627,49 +649,47 @@ nsClipboard::SelectionGetEvent (GtkWidge
nsMemory::Free(primitive_data);
}
g_free(target_name);
}
void
-nsClipboard::SelectionClearEvent (GtkWidget *aWidget,
- GdkEventSelection *aEvent)
+nsClipboard::SelectionClearEvent(GtkClipboard *aGtkClipboard)
{
PRInt32 whichClipboard;
// which clipboard?
- if (aEvent->selection == GDK_SELECTION_PRIMARY)
+ if (aGtkClipboard == gtk_clipboard_get(GDK_SELECTION_PRIMARY))
whichClipboard = kSelectionClipboard;
- else if (aEvent->selection == GDK_SELECTION_CLIPBOARD)
+ else if (aGtkClipboard == gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))
whichClipboard = kGlobalClipboard;
else
return; // THAT AIN'T NO CLIPBOARD I EVER HEARD OF
EmptyClipboard(whichClipboard);
}
void
-invisible_selection_get_cb (GtkWidget *aWidget,
- GtkSelectionData *aSelectionData,
- guint aTime,
- guint aInfo,
- nsClipboard *aClipboard)
+clipboard_get_cb(GtkClipboard *aGtkClipboard,
+ GtkSelectionData *aSelectionData,
+ guint info,
+ gpointer user_data)
{
- aClipboard->SelectionGetEvent(aWidget, aSelectionData, aTime);
+ nsClipboard *aClipboard = static_cast<nsClipboard *>(user_data);
+ aClipboard->SelectionGetEvent(aGtkClipboard, aSelectionData);
}
-gboolean
-selection_clear_event_cb (GtkWidget *aWidget,
- GdkEventSelection *aEvent,
- nsClipboard *aClipboard)
+void
+clipboard_clear_cb(GtkClipboard *aGtkClipboard,
+ gpointer user_data)
{
- aClipboard->SelectionClearEvent(aWidget, aEvent);
- return TRUE;
+ nsClipboard *aClipboard = static_cast<nsClipboard *>(user_data);
+ aClipboard->SelectionClearEvent(aGtkClipboard);
}
/*
* when copy-paste, mozilla wants data encoded using UCS2,
* other app such as StarOffice use "text/html"(RFC2854).
* This function convert data(got from GTK clipboard)
* to data mozilla wanted.
*