[Patch] A clipboard daemon for gnome-settings-daemon



A while ago there has been a discussion about integrating a clipboard daemon 
in GNOME which keeps the content of the clipboard in memory, so that even if 
the owner application exits the clipboard will not be lost.
Here's a patch for gnome-settings-daemon (against most recent anonymous CVS) 
which does exactly that. No configuration options - it's supposed to Just 
Work(tm).
I've tested this extensively for several weeks and it works fine (including QT 
and Mozilla apps).
This patch can also be applied against the latest stable release of 
control-center.
? stamp-h1
? gnome-settings-daemon/gnome-clipboard-daemon.c
? gnome-settings-daemon/gnome-clipboard-daemon.h
? gnome-settings-daemon/selection-data-list.c
? gnome-settings-daemon/selection-data-list.h
Index: gnome-settings-daemon/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-control-center/gnome-settings-daemon/Makefile.am,v
retrieving revision 1.31
diff -u -r1.31 Makefile.am
--- gnome-settings-daemon/Makefile.am	29 Jul 2003 09:22:27 -0000	1.31
+++ gnome-settings-daemon/Makefile.am	5 Sep 2003 18:13:33 -0000
@@ -10,6 +10,10 @@
 	factory.c			\
 	gnome-settings-daemon.h		\
 	gnome-settings-daemon.c		\
+	gnome-clipboard-daemon.c	\
+	gnome-clipboard-daemon.h	\
+	selection-data-list.c		\
+	selection-data-list.h		\
 	gnome-settings-font.h		\
 	gnome-settings-font.c		\
 	gnome-settings-mouse.h		\
Index: gnome-settings-daemon/gnome-settings-daemon.c
===================================================================
RCS file: /cvs/gnome/gnome-control-center/gnome-settings-daemon/gnome-settings-daemon.c,v
retrieving revision 1.31
diff -u -r1.31 gnome-settings-daemon.c
--- gnome-settings-daemon/gnome-settings-daemon.c	26 Jun 2003 11:40:08 -0000	1.31
+++ gnome-settings-daemon/gnome-settings-daemon.c	5 Sep 2003 18:13:33 -0000
@@ -40,6 +40,7 @@
 #include "xsettings-manager.h"
 #include "gnome-settings-daemon.h"
 
+#include "gnome-clipboard-daemon.h"
 /*#include "gnome-settings-disk.h"*/
 #include "gnome-settings-font.h"
 #include "gnome-settings-xsettings.h"
@@ -268,6 +269,7 @@
    */
   client = gconf_client_get_default ();
 
+  gnome_clipboard_daemon_start ();
 /*  gnome_settings_disk_init (client);*/
   gnome_settings_font_init (client);
   gnome_settings_xsettings_init (client);
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ gnome-settings-daemon/gnome-clipboard-daemon.h	Fri Sep  5 19:59:17 2003
@@ -0,0 +1,29 @@
+/*  GNOME Clipboard Daemon
+ *  Copyright (C) 2003  Hongli Lai <h lai chello nl>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GNOME_CLIPBOARD_DAEMON_H_
+#define _GNOME_CLIPBOARD_DAEMON_H_
+
+#include <glib.h>
+
+gboolean gnome_clipboard_daemon_start (void);
+
+#endif /* _GNOME_CLIPBOARD_DAEMON_H_ */
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ gnome-settings-daemon/gnome-clipboard-daemon.c	Fri Sep  5 19:59:19 2003
@@ -0,0 +1,189 @@
+/*  GNOME Clipboard Daemon
+ *  Copyright (C) 2003  Hongli Lai <h lai chello nl>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gconf/gconf.h>
+#include <libgnome/gnome-init.h>
+#include <libgnomeui/gnome-ui-init.h>
+#include <config.h>
+
+#include <string.h>
+#include "selection-data-list.h"
+
+
+static GtkClipboard *clipboard = NULL;
+static GdkAtom targets_atom = GDK_NONE;
+static SelectionDataList *clipboard_saved = NULL;
+
+static gboolean check_clipboard (gpointer user_data);
+
+
+/* Free the saved clipboard data */
+static void
+free_saved_data ()
+{
+	if (!clipboard_saved) return;
+	selection_data_list_free (clipboard_saved);
+	clipboard_saved = NULL;
+}
+
+
+/* Save the current clipboard data */
+static gboolean
+save_clipboard_data (GtkSelectionData *content)
+{
+	GdkAtom *atoms = NULL;
+	gint i, count;
+
+	free_saved_data ();
+	clipboard_saved = selection_data_list_new ();
+
+	if (!gtk_selection_data_get_targets (content, &atoms, &count))
+	    {
+		/* The type generated by KDE apps is named "TARGETS", but it's 92, which does
+		   not equal GDK_SELECTION_TYPE_ATOM (4). That's why gtk_selection_data_get_targets()
+		   fails. */
+
+		count = content->length / sizeof (Atom);
+		atoms = g_new0 (GdkAtom, count);
+
+		for (i = 0; i < count; i++)
+			atoms[i] = gdk_x11_xatom_to_atom ((Atom) content->data[i * sizeof (Atom)]);
+	    }
+
+	for (i = 0; i < count; i++)
+	    {
+		GtkSelectionData *data;
+		gchar *name;
+
+		name = gdk_atom_name (atoms[i]);
+		if (!name) continue;
+
+		data = gtk_clipboard_wait_for_contents (clipboard, atoms[i]);
+		selection_data_list_add (clipboard_saved, name, data);
+	    }
+
+	g_free (atoms);
+	gtk_selection_data_free (content);
+	return TRUE;
+}
+
+
+static void
+clipboard_get_func (GtkClipboard *cb, GtkSelectionData *data, guint info, gpointer user_data_or_owner)
+{
+	SelectionDataEntry *data_entry;
+
+	data_entry = GINT_TO_POINTER ((guint) info);
+	gtk_selection_data_set (data, data_entry->data->type, data_entry->data->format,
+		data_entry->data->data, data_entry->data->length);
+}
+
+
+/* We lost ownership */
+static void
+clipboard_clear_func (GtkClipboard *cb, gpointer user_data_or_owner)
+{
+	/* Try to reclaim it */
+	check_clipboard (GINT_TO_POINTER (TRUE));
+}
+
+
+/* Restore the clipboard from saved data and claim ownership */
+static void
+claim_clipboard ()
+{
+	GtkTargetEntry *targets;
+	guint n_targets = 0;
+
+	targets = selection_data_list_make_targets (clipboard_saved, &n_targets);
+	if (!gtk_clipboard_set_with_data (clipboard, targets, n_targets,
+	    clipboard_get_func, clipboard_clear_func, NULL))
+		gtk_timeout_add (1500, check_clipboard, NULL);
+	g_free (targets);
+}
+
+
+static gboolean
+check_clipboard (gpointer reclaim)
+{
+	GtkSelectionData *content;
+
+	content = gtk_clipboard_wait_for_contents (clipboard, targets_atom);
+	if (content)
+	    {
+		gchar *name;
+		gboolean saved = FALSE;
+
+		/* Save the clipboard content and claim ownership */
+		name = gdk_atom_name (content->type);
+		if (name && (strcmp (name, "ATOM") == 0
+		 || (strcmp (name, "TARGETS") == 0 && content->length > -1)))
+			saved = save_clipboard_data (content);
+		else
+			g_print ("Unknown atom %s???\n", name);
+		g_free (name);
+
+		if (saved)
+			claim_clipboard ();
+		else
+			/* Saving failed; try again */
+			gtk_timeout_add (500, check_clipboard, NULL);
+	    }
+	else if (GPOINTER_TO_INT (reclaim))
+		/* We lost the clipboard ownership but the new clipboard doesn't have data.
+		   Mozilla does this. Reclaim the clipboard */
+		claim_clipboard ();
+	else
+		/* No clipboard data; try again */
+		gtk_timeout_add (500, check_clipboard, NULL);
+
+	return FALSE;
+}
+
+
+gboolean
+gnome_clipboard_daemon_start ()
+{
+	GdkAtom daemon;
+
+	/* Check if a clipboard daemon is already started */
+	daemon = gdk_atom_intern ("CLIPBOARD_MANAGER", FALSE);
+	if (XGetSelectionOwner (gdk_x11_get_default_xdisplay (), gdk_x11_atom_to_xatom (daemon)) != None)
+	    {
+		/* Yes; try to start the daemon again in 3 seconds */
+		gtk_timeout_add (3000, (GtkFunction) gnome_clipboard_daemon_start, NULL);
+		return FALSE;
+	    }
+
+	/* Indicate that we've already started */
+	gtk_selection_owner_set (gtk_invisible_new (), daemon, GDK_CURRENT_TIME);
+
+
+	/* Initialize */
+	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+	targets_atom = gdk_atom_intern ("TARGETS", FALSE);
+
+	check_clipboard (NULL);
+
+	return FALSE;
+}
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ gnome-settings-daemon/selection-data-list.h	Fri Sep  5 19:59:27 2003
@@ -0,0 +1,59 @@
+/*  GNOME Clipboard Daemon
+ *  Copyright (C) 2003  Hongli Lai <h lai chello nl>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SELECTION_DATA_LIST_H_
+#define _SELECTION_DATA_LIST_H_
+
+
+#include <gtk/gtk.h>
+
+/* Simple wrapper structures for saving clipboard data */
+
+
+typedef struct _SelectionDataEntry SelectionDataEntry;
+typedef struct _SelectionDataList SelectionDataList;
+
+
+struct _SelectionDataEntry
+{
+	gchar *name;
+	GtkSelectionData *data;
+};
+
+
+SelectionDataEntry *selection_data_entry_new (gchar *name, GtkSelectionData *data);
+void selection_data_entry_free (SelectionDataEntry *entry);
+
+
+struct _SelectionDataList
+{
+	GList *entries;
+};
+
+
+SelectionDataList *selection_data_list_new (void);
+void selection_data_list_free (SelectionDataList *list);
+
+void selection_data_list_add (SelectionDataList *list, gchar *atom_name, GtkSelectionData *data);
+GtkTargetEntry *selection_data_list_make_targets (SelectionDataList *list, guint *n_targets);
+
+
+#endif /* _SELECTION_DATA_LIST_H_ */
--- /dev/null	Thu Apr 11 16:25:15 2002
+++ gnome-settings-daemon/selection-data-list.c	Fri Sep  5 19:59:24 2003
@@ -0,0 +1,111 @@
+/*  GNOME Clipboard Daemon
+ *  Copyright (C) 2003  Hongli Lai <h lai chello nl>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Red Hat makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "selection-data-list.h"
+
+
+SelectionDataEntry *
+selection_data_entry_new (gchar *name, GtkSelectionData *data)
+{
+	SelectionDataEntry *entry;
+
+	g_return_val_if_fail (name != NULL, NULL);
+
+	entry = (SelectionDataEntry *) g_new0 (SelectionDataEntry, 1);
+	entry->name = name;
+	entry->data = data;
+	return entry;
+}
+
+
+void
+selection_data_entry_free (SelectionDataEntry *entry)
+{
+	g_return_if_fail (entry != NULL);
+
+	g_free (entry->name);
+	if (entry->data) gtk_selection_data_free (entry->data);
+	g_free (entry);
+}
+
+
+SelectionDataList *
+selection_data_list_new ()
+{
+	SelectionDataList *list;
+
+	list = (SelectionDataList *) g_new0 (SelectionDataList, 1);
+	return list;
+}
+
+
+void
+selection_data_list_free (SelectionDataList *list)
+{
+	GList *elist;
+
+	g_return_if_fail (list != NULL);
+
+	for (elist = list->entries; elist; elist = elist->next)
+		selection_data_entry_free ((SelectionDataEntry *) elist->data);
+	g_list_free (list->entries);
+	g_free (list);
+}
+
+
+void
+selection_data_list_add (SelectionDataList *list, gchar *atom_name, GtkSelectionData *data)
+{
+	SelectionDataEntry *entry;
+
+	g_return_if_fail (list != NULL);
+	g_return_if_fail (atom_name != NULL);
+
+	entry = selection_data_entry_new (atom_name, data);
+	list->entries = g_list_append (list->entries, entry);
+}
+
+
+GtkTargetEntry *
+selection_data_list_make_targets (SelectionDataList *list, guint *n_targets)
+{
+	GList *elist;
+	GtkTargetEntry *entries;
+	guint i = 0;
+
+	g_return_val_if_fail (list != NULL, NULL);
+	g_return_val_if_fail (n_targets != NULL, NULL);
+
+	entries = (GtkTargetEntry *) g_new0 (GtkTargetEntry, g_list_length (list->entries));
+	for (elist = list->entries; elist; elist = elist->next)
+	{
+		SelectionDataEntry *data_entry = (SelectionDataEntry *) elist->data;
+
+		entries[i].target = data_entry->name;
+		entries[i].info = (guint) GPOINTER_TO_INT (data_entry);
+		if (data_entry->data)
+			entries[i].flags = (guint) data_entry->data->type;
+		i++;
+	}
+	*n_targets = i;
+
+	return entries;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]