mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 311340 - "Clipboard data is lost on exit (Should implement the freedesktop.org specification for clipboard management)" [r=karlt]
This commit is contained in:
parent
81d6db5548
commit
2150aa916b
@ -46,6 +46,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsImageToPixbuf.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "imgIContainer.h"
|
||||
|
||||
@ -62,19 +63,18 @@
|
||||
#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);
|
||||
|
||||
gboolean
|
||||
selection_clear_event_cb (GtkWidget *aWidget,
|
||||
GdkEventSelection *aEvent,
|
||||
nsClipboard *aClipboard);
|
||||
clipboard_get_cb(GtkClipboard *aGtkClipboard,
|
||||
GtkSelectionData *aSelectionData,
|
||||
guint info,
|
||||
gpointer user_data);
|
||||
|
||||
// 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,
|
||||
@ -121,33 +121,46 @@ clipboard_text_received(GtkClipboard *clipboard,
|
||||
gpointer data);
|
||||
|
||||
nsClipboard::nsClipboard()
|
||||
{
|
||||
mWidget = nsnull;
|
||||
{
|
||||
}
|
||||
|
||||
nsClipboard::~nsClipboard()
|
||||
{
|
||||
if (mWidget)
|
||||
gtk_widget_destroy(mWidget);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsClipboard, nsIClipboard)
|
||||
|
||||
nsresult
|
||||
nsClipboard::Init(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
|
||||
{
|
||||
mWidget = gtk_invisible_new();
|
||||
if (!mWidget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
g_signal_connect(G_OBJECT(mWidget), "selection_get",
|
||||
G_CALLBACK(invisible_selection_get_cb), this);
|
||||
|
||||
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
|
||||
if (strcmp(aTopic, "quit-application") == 0) {
|
||||
// application is going to quit, save clipboard content
|
||||
Store();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -176,24 +189,8 @@ nsClipboard::SetData(nsITransferable *aTransferable,
|
||||
// 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;
|
||||
@ -203,7 +200,7 @@ nsClipboard::SetData(nsITransferable *aTransferable,
|
||||
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++) {
|
||||
@ -218,13 +215,10 @@ nsClipboard::SetData(nsITransferable *aTransferable,
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -233,26 +227,53 @@ nsClipboard::SetData(nsITransferable *aTransferable,
|
||||
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
|
||||
@ -489,15 +510,8 @@ nsClipboard::GetTransferable(PRInt32 aWhichClipboard)
|
||||
}
|
||||
|
||||
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
|
||||
@ -515,7 +529,15 @@ nsClipboard::SelectionGetEvent (GtkWidget *aWidget,
|
||||
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;
|
||||
@ -632,15 +654,14 @@ nsClipboard::SelectionGetEvent (GtkWidget *aWidget,
|
||||
}
|
||||
|
||||
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
|
||||
@ -649,22 +670,21 @@ nsClipboard::SelectionClearEvent (GtkWidget *aWidget,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -44,7 +44,8 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
class nsClipboard : public nsIClipboard
|
||||
class nsClipboard : public nsIClipboard,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
nsClipboard();
|
||||
@ -53,33 +54,29 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSICLIPBOARD
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// Make sure we are initialized, called from the factory
|
||||
// constructor
|
||||
nsresult Init (void);
|
||||
// Someone requested the selection from the hidden widget
|
||||
void SelectionGetEvent (GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData,
|
||||
guint aTime);
|
||||
void SelectionClearEvent (GtkWidget *aWidget,
|
||||
GdkEventSelection *aEvent);
|
||||
nsresult Init (void);
|
||||
|
||||
// Someone requested the selection
|
||||
void SelectionGetEvent (GtkClipboard *aGtkClipboard,
|
||||
GtkSelectionData *aSelectionData);
|
||||
void SelectionClearEvent (GtkClipboard *aGtkClipboard);
|
||||
|
||||
private:
|
||||
// Utility methods
|
||||
static GdkAtom GetSelectionAtom (PRInt32 aWhichClipboard);
|
||||
static GtkSelectionData *GetTargets (GdkAtom aWhichClipboard);
|
||||
|
||||
// Save global clipboard content to gtk
|
||||
nsresult Store (void);
|
||||
|
||||
// Get our hands on the correct transferable, given a specific
|
||||
// clipboard
|
||||
nsITransferable *GetTransferable (PRInt32 aWhichClipboard);
|
||||
|
||||
// Add a target type to the hidden widget
|
||||
void AddTarget (GdkAtom aName,
|
||||
GdkAtom aClipboard);
|
||||
|
||||
// The hidden widget where we do all of our operations
|
||||
GtkWidget *mWidget;
|
||||
// Hang on to our owners and transferables so we can transfer data
|
||||
// when asked.
|
||||
nsCOMPtr<nsIClipboardOwner> mSelectionOwner;
|
||||
|
Loading…
Reference in New Issue
Block a user