[remmina] Add clipboard support (#818155)

Christoph Wickert cwickert at fedoraproject.org
Fri Jun 1 14:56:19 UTC 2012


commit 8a5eb05ef58566580355a45072516f0d3ed50a44
Author: Christoph Wickert <cwickert at fedoraproject.org>
Date:   Fri Jun 1 16:56:14 2012 +0200

    Add clipboard support (#818155)
    
    - Fix a memory leak and a crash

 remmina-1.0.0-add-clipboard-support.patch     |  663 +++++++++++++++++++++++++
 remmina-1.0.0-clipboard-bugfix.patch          |   73 +++
 remmina-1.0.0-fix-crashes-in-some-cases.patch |   71 +++
 remmina-1.0.0-fix-memory-leak.patch           |   24 +
 remmina-1.0.0-some-more-clipboard-fixes.patch |  180 +++++++
 remmina.spec                                  |   26 +-
 6 files changed, 1036 insertions(+), 1 deletions(-)
---
diff --git a/remmina-1.0.0-add-clipboard-support.patch b/remmina-1.0.0-add-clipboard-support.patch
new file mode 100644
index 0000000..b5fd340
--- /dev/null
+++ b/remmina-1.0.0-add-clipboard-support.patch
@@ -0,0 +1,663 @@
+From 3ebdd6e7b0ee53ecdaf0d14bada6b92e7334b12a Mon Sep 17 00:00:00 2001
+From: Jean-Louis Dupond <jean-louis at dupond.be>
+Date: Mon, 30 Apr 2012 23:10:04 +0200
+Subject: [PATCH] Add clipboard support
+
+---
+ remmina-plugins/rdp/CMakeLists.txt |    2 +
+ remmina-plugins/rdp/rdp_cliprdr.c  |  459 ++++++++++++++++++++++++++++++++++++
+ remmina-plugins/rdp/rdp_cliprdr.h  |   33 +++
+ remmina-plugins/rdp/rdp_event.c    |   19 ++
+ remmina-plugins/rdp/rdp_plugin.c   |   15 ++
+ remmina-plugins/rdp/rdp_plugin.h   |    6 +-
+ 6 files changed, 533 insertions(+), 1 deletion(-)
+ create mode 100644 remmina-plugins/rdp/rdp_cliprdr.c
+ create mode 100644 remmina-plugins/rdp/rdp_cliprdr.h
+
+diff --git a/remmina-plugins/rdp/CMakeLists.txt b/remmina-plugins/rdp/CMakeLists.txt
+index e3ec20b..8ae4a4d 100644
+--- a/remmina-plugins/rdp/CMakeLists.txt
++++ b/remmina-plugins/rdp/CMakeLists.txt
+@@ -33,6 +33,8 @@ set(REMMINA_PLUGIN_RDP_SRCS
+ 	rdp_gdi.h
+ 	rdp_graphics.c
+ 	rdp_graphics.h
++	rdp_cliprdr.c
++	rdp_cliprdr.h
+ 	)
+ 
+ add_library(remmina-plugin-rdp ${REMMINA_PLUGIN_RDP_SRCS})
+diff --git a/remmina-plugins/rdp/rdp_cliprdr.c b/remmina-plugins/rdp/rdp_cliprdr.c
+new file mode 100644
+index 0000000..0821ffa
+--- /dev/null
++++ b/remmina-plugins/rdp/rdp_cliprdr.c
+@@ -0,0 +1,459 @@
++/*
++ * Remmina - The GTK+ Remote Desktop Client
++ * Copyright (C) 2012-2012 Jean-Louis Dupond
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, 
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include "rdp_plugin.h"
++#include "rdp_cliprdr.h"
++
++#include <freerdp/freerdp.h>
++#include <freerdp/utils/memory.h>
++#include <freerdp/channels/channels.h>
++#include <freerdp/plugins/cliprdr.h>
++
++/*
++ * Get the formats we can export based on the current clipboard data.
++ */
++void remmina_rdp_cliprdr_get_target_types(uint32** dst_formats, uint16* size, GdkAtom* types, int count)
++{
++	int i;
++	gboolean image = FALSE;
++	gboolean text = FALSE;
++	gboolean textutf8 = FALSE;
++	int matches = 1;
++	uint32* formats = (uint32*) xmalloc(sizeof(uint32) * 10);
++
++	formats[0] = CB_FORMAT_RAW;	
++	for (i = 0; i < count; i++)
++	{	
++		GdkAtom atom = GDK_POINTER_TO_ATOM(types[i]);
++		gchar* name = gdk_atom_name(atom);
++		if (g_strcmp0("UTF8_STRING", name) == 0 || g_strcmp0("text/plain;charset=utf-8", name) == 0)
++		{
++			textutf8 = TRUE;
++		}
++		if (g_strcmp0("TEXT", name) == 0 || g_strcmp0("text/plain", name) == 0)
++		{
++			text = TRUE;
++		}
++		if (g_strcmp0("text/html", name) == 0)
++		{
++			formats[matches] = CB_FORMAT_HTML;
++			matches++;
++		}
++		if (g_strcmp0("image/png", name) == 0)
++		{
++			formats[matches] = CB_FORMAT_PNG;
++			image = TRUE;
++			matches++;
++		}
++		if (g_strcmp0("image/jpeg", name) == 0)
++		{
++			formats[matches] = CB_FORMAT_JPEG;
++			image = TRUE;
++			matches++;
++		}
++		if (g_strcmp0("image/bmp", name) == 0)
++		{
++			formats[matches] = CB_FORMAT_DIB;
++			image = TRUE;
++			matches++;
++		}
++	}
++	//Only add text formats if we don't have image formats
++	if (!image)
++	{
++		if (textutf8)
++		{
++			formats[matches] = CB_FORMAT_UNICODETEXT;
++			matches++;
++		}
++		if (text)
++		{
++			formats[matches] = CB_FORMAT_TEXT;
++			matches++;
++		}
++	}
++
++	*size = (uint16)matches;
++	*dst_formats = (uint32*) xmalloc(sizeof(uint32) * matches);
++	memcpy(*dst_formats, formats, sizeof(uint32) * matches);
++	g_free(formats);
++}
++
++int remmina_rdp_cliprdr_send_format_list_event(RemminaProtocolWidget* gp)
++{
++	GtkClipboard* clipboard;
++	GdkAtom* targets;
++	gboolean result = 0;
++	gint count;
++	RDP_EVENT* rdp_event;
++	RDP_CB_FORMAT_LIST_EVENT* format_list_event;
++	rfContext* rfi = GET_DATA(gp);
++
++	/* Lets see if we have something in our clipboard */
++	THREADS_ENTER
++	clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
++	if (clipboard)
++	{
++		result = gtk_clipboard_wait_for_targets(clipboard, &targets, &count);
++	}
++	THREADS_LEAVE
++	
++	if (!result)
++		return 1;
++
++	int i;
++	for (i = 0; i < count; i++)
++	{
++		g_printf("Target %d: %s\n", i, gdk_atom_name(targets[i]));
++	}
++
++	rdp_event = (RDP_EVENT*) xnew(RDP_CB_FORMAT_LIST_EVENT);
++	rdp_event->event_class = RDP_EVENT_CLASS_CLIPRDR;
++	rdp_event->event_type = RDP_EVENT_TYPE_CB_FORMAT_LIST;
++	format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) rdp_event;
++	
++	remmina_rdp_cliprdr_get_target_types(&format_list_event->formats, &format_list_event->num_formats, targets, count);
++	g_free(targets);
++
++	int num_formats = format_list_event->num_formats;
++	g_printf("Sending %d formats\n", num_formats);
++	for (i = 0; i < num_formats; i++)
++	{
++		g_printf("Sending format %#X\n", format_list_event->formats[i]);
++	}
++	
++	return freerdp_channels_send_event(rfi->channels, (RDP_EVENT*) format_list_event);
++}
++
++static uint8* lf2crlf(uint8* data, int* size)
++{
++        uint8 c;
++        uint8* outbuf;
++        uint8* out;
++        uint8* in_end;
++        uint8* in;
++        int out_size;
++
++        out_size = (*size) * 2 + 1;
++        outbuf = (uint8*) xmalloc(out_size);
++        out = outbuf;
++        in = data;
++        in_end = data + (*size);
++
++        while (in < in_end)
++        {
++                c = *in++;
++                if (c == '\n')
++                {
++                        *out++ = '\r';
++                        *out++ = '\n';
++                }
++                else
++                {
++                        *out++ = c;
++                }
++        }
++
++        *out++ = 0;
++        *size = out - outbuf;
++
++        return outbuf;
++}
++
++static void crlf2lf(uint8* data, int* size)
++{
++        uint8 c;
++        uint8* out;
++        uint8* in;
++        uint8* in_end;
++
++        out = data;
++        in = data;
++        in_end = data + (*size);
++
++        while (in < in_end)
++        {
++                c = *in++;
++
++                if (c != '\r')
++                        *out++ = c;
++        }
++
++        *size = out - data;
++}
++
++uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, int* size)
++{
++	g_printf("GetData: Requested Format: %#X\n", format);
++	rfContext* rfi = GET_DATA(gp);
++	GtkClipboard* clipboard;
++	uint8* inbuf = NULL;
++	uint8* outbuf = NULL;
++	GdkPixbuf *image = NULL;
++	
++	THREADS_ENTER
++	clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
++	if (clipboard)
++	{
++		if (format == CB_FORMAT_TEXT || format == CB_FORMAT_UNICODETEXT || format == CB_FORMAT_HTML)
++		{
++			inbuf = (uint8*)gtk_clipboard_wait_for_text(clipboard);
++		}
++		if (format == CB_FORMAT_PNG || format == CB_FORMAT_JPEG || format == CB_FORMAT_DIB)
++		{
++			image = gtk_clipboard_wait_for_image(clipboard);
++		}
++	}
++	THREADS_LEAVE
++
++	if (format == CB_FORMAT_TEXT || format == CB_FORMAT_HTML || format == CB_FORMAT_UNICODETEXT)
++	{
++		lf2crlf(inbuf, size);
++		if (format == CB_FORMAT_TEXT)
++		{
++			outbuf = inbuf;
++		}
++		if (format == CB_FORMAT_HTML)
++		{
++			//TODO: check if we need special handling for HTML
++			outbuf = inbuf;
++		}
++		if (format == CB_FORMAT_UNICODETEXT)
++		{
++			size_t out_size;
++			UNICONV* uniconv;
++			
++			uniconv = freerdp_uniconv_new();
++			outbuf = (uint8*) freerdp_uniconv_out(uniconv, (char*) inbuf, &out_size);
++			freerdp_uniconv_free(uniconv);
++			*size = out_size + 2;
++		}
++	}
++	if (format == CB_FORMAT_PNG || format == CB_FORMAT_JPEG || format == CB_FORMAT_DIB)
++	{
++		gchar* data;
++		gsize buffersize;
++		if (format == CB_FORMAT_PNG)
++		{
++			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "png", NULL, NULL);
++			memcpy(outbuf, data, buffersize);
++		}
++		if (format == CB_FORMAT_JPEG)
++		{
++			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "jpeg", NULL, NULL);
++			memcpy(outbuf, data, buffersize);
++		}
++		if (format == CB_FORMAT_DIB)
++		{
++			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "bmp", NULL, NULL);
++			*size = buffersize - 14;
++			g_printf("Size of pixels: %d\n", *size);
++			outbuf = (uint8*) xmalloc(*size);
++			memcpy(outbuf, data + 14, *size);
++		}
++	}
++	
++	if (!outbuf)
++		outbuf = (uint8*)"";
++
++	return outbuf;
++}
++
++void remmina_rdp_cliprdr_parse_response_event(RemminaProtocolWidget* gp, RDP_EVENT* event)
++{
++	g_printf("Received RDP_EVENT_TYPE_CB_DATA_RESPONSE\n");
++
++	GtkClipboard* clipboard;
++	GdkPixbuf *image = NULL;
++	uint8* data;
++	int size;
++	gboolean text = FALSE;
++	gboolean img = FALSE;
++	rfContext* rfi = GET_DATA(gp);
++	RDP_CB_DATA_RESPONSE_EVENT* data_response_event;
++
++	data_response_event = (RDP_CB_DATA_RESPONSE_EVENT*) event;
++	data = data_response_event->data;
++	size = data_response_event->size;
++
++	g_printf("Requested format was: 0x%x\n", rfi->requested_format);
++	
++	if (rfi->requested_format == CB_FORMAT_TEXT || rfi->requested_format == CB_FORMAT_UNICODETEXT || rfi->requested_format == CB_FORMAT_HTML)
++	{
++		if (rfi->requested_format == CB_FORMAT_UNICODETEXT)
++		{
++			UNICONV* uniconv;
++
++			uniconv = freerdp_uniconv_new();
++			data = (uint8*) freerdp_uniconv_in(uniconv, data, size);
++			size = strlen((char*) data);
++			freerdp_uniconv_free(uniconv);
++		}
++		crlf2lf(data, &size);
++		text = TRUE;
++	}
++	if (rfi->requested_format == CB_FORMAT_DIB || rfi->requested_format == CB_FORMAT_PNG || rfi->requested_format == CB_FORMAT_JPEG)
++	{
++		/* Reconstruct header */
++		if (rfi->requested_format == CB_FORMAT_DIB)
++		{
++			STREAM* s;
++			uint16 bpp;
++			uint32 offset;
++			uint32 ncolors;
++
++			s = stream_new(0);
++			stream_attach(s, data, size);
++			stream_seek(s, 14);
++			stream_read_uint16(s, bpp);
++			stream_read_uint32(s, ncolors);
++			offset = 14 + 40 + (bpp <= 8 ? (ncolors == 0 ? (1 << bpp) : ncolors) * 4 : 0);
++			stream_detach(s);
++			stream_free(s);
++
++			s = stream_new(14 + size);
++			stream_write_uint8(s, 'B');
++			stream_write_uint8(s, 'M');
++			stream_write_uint32(s, 14 + size);
++			stream_write_uint32(s, 0);
++			stream_write_uint32(s, offset);
++			stream_write(s, data, size);
++
++			data = stream_get_head(s);
++			size = stream_get_length(s);
++			stream_detach(s);
++			stream_free(s);
++		}
++		GdkPixbufLoader *pixbuf;
++		pixbuf = gdk_pixbuf_loader_new();
++		gdk_pixbuf_loader_write(pixbuf, data, size, NULL);
++		image = gdk_pixbuf_loader_get_pixbuf(pixbuf);
++		img = TRUE;
++	}
++
++	THREADS_ENTER
++	clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
++	if (clipboard)
++	{
++		if (text || img)
++			rfi->clipboard_wait = TRUE;
++		if (text)
++			gtk_clipboard_set_text(clipboard, (gchar*)data, size);		
++		if (img)
++			gtk_clipboard_set_image(clipboard, image);
++	}
++	THREADS_LEAVE
++	
++}
++
++void remmina_handle_channel_event(RemminaProtocolWidget* gp, RDP_EVENT* event)
++{
++	RDP_EVENT* rdp_event = NULL;
++	rfContext* rfi = GET_DATA(gp);
++
++	switch (event->event_class)
++	{
++		case RDP_EVENT_CLASS_CLIPRDR:
++			g_printf("Event ID: %d\n", event->event_type);
++			if (event->event_type == RDP_EVENT_TYPE_CB_MONITOR_READY)
++			{
++				g_printf("Received CB_MONITOR_READY - Sending RDP_EVENT_TYPE_CB_FORMAT_LIST\n");
++				/* Sending our format list */
++				remmina_rdp_cliprdr_send_format_list_event(gp);
++			}
++			if (event->event_type == RDP_EVENT_TYPE_CB_FORMAT_LIST)
++			{
++				/* We received a FORMAT_LIST from the server, update our clipboard */
++				g_printf("Received RDP_EVENT_TYPE_CB_FORMAT_LIST\n");
++				int i;	
++				uint32 format = CB_FORMAT_RAW;	
++				RDP_CB_FORMAT_LIST_EVENT* format_list_event;
++
++				format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event;
++
++				g_printf("Format List Size: %d\n", format_list_event->num_formats);
++				for (i = 0; i < format_list_event->num_formats; i++)
++				{
++					g_printf("Format: 0x%X\n", format_list_event->formats[i]);
++					if (format_list_event->formats[i] == CB_FORMAT_UNICODETEXT)
++					{
++						format = CB_FORMAT_UNICODETEXT;
++						break;
++					}
++					if (format_list_event->formats[i] == CB_FORMAT_DIB)
++					{
++						format = CB_FORMAT_DIB;
++						break;
++					}
++					if (format_list_event->formats[i] == CB_FORMAT_JPEG)
++					{
++						format = CB_FORMAT_JPEG;
++						break;
++					}
++					if (format_list_event->formats[i] == CB_FORMAT_PNG)
++					{
++						format = CB_FORMAT_PNG;
++						break;
++					}
++					if (format_list_event->formats[i] == CB_FORMAT_TEXT)
++					{
++						format = CB_FORMAT_TEXT;
++						break;
++					}				
++				}
++				rfi->requested_format = format;
++				
++				g_printf("Format Requested: 0x%X\n", format);
++				/* Request Clipboard data of the server */
++				RDP_CB_DATA_REQUEST_EVENT* data_request_event;
++				rdp_event = (RDP_EVENT*) xnew(RDP_CB_DATA_REQUEST_EVENT);
++				rdp_event->event_class = RDP_EVENT_CLASS_CLIPRDR;
++				rdp_event->event_type = RDP_EVENT_TYPE_CB_DATA_REQUEST;
++				data_request_event = (RDP_CB_DATA_REQUEST_EVENT*) rdp_event;
++				data_request_event->format = format;
++				freerdp_channels_send_event(rfi->channels, (RDP_EVENT*) data_request_event);
++			}
++			if (event->event_type == RDP_EVENT_TYPE_CB_DATA_REQUEST)
++			{	
++				g_printf("Received RDP_EVENT_TYPE_CB_DATA_REQUEST\n");
++				
++				uint8* data;
++				int size;
++				RDP_CB_DATA_REQUEST_EVENT* data_request_event = (RDP_CB_DATA_REQUEST_EVENT*) event;
++				RDP_CB_DATA_RESPONSE_EVENT* data_response_event;
++
++				g_printf("Event Format: %d\n", data_request_event->format);
++
++				/* Send Data */
++				rdp_event = (RDP_EVENT*) xnew(RDP_CB_DATA_RESPONSE_EVENT);
++				rdp_event->event_class = RDP_EVENT_CLASS_CLIPRDR;
++				rdp_event->event_type = RDP_EVENT_TYPE_CB_DATA_RESPONSE;
++				data_response_event = (RDP_CB_DATA_RESPONSE_EVENT*) rdp_event;
++				data = remmina_rdp_cliprdr_get_data(gp, data_request_event->format, &size);
++				data_response_event->data = data;
++				data_response_event->size = size;
++				freerdp_channels_send_event(rfi->channels, rdp_event);
++			}
++			if (event->event_type == RDP_EVENT_TYPE_CB_DATA_RESPONSE)
++			{
++				remmina_rdp_cliprdr_parse_response_event(gp, event);
++			}
++	}
++}
+diff --git a/remmina-plugins/rdp/rdp_cliprdr.h b/remmina-plugins/rdp/rdp_cliprdr.h
+new file mode 100644
+index 0000000..ed6bf70
+--- /dev/null
++++ b/remmina-plugins/rdp/rdp_cliprdr.h
+@@ -0,0 +1,33 @@
++/*
++ * Remmina - The GTK+ Remote Desktop Client
++ * Copyright (C) 2010-2011 Vic Lee
++ * Copyright (C) 2012-2012 Jean-Louis Dupond
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, 
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __REMMINA_RDP_CLIPRDR_H__
++#define __REMMINA_RDP_CLIPRDR_H__
++
++G_BEGIN_DECLS
++
++RDP_EVENT* remmina_rdp_cliprdr_get_event(uint16 event_type);
++int remmina_rdp_cliprdr_send_format_list_event(RemminaProtocolWidget* gp);
++void remmina_handle_channel_event(RemminaProtocolWidget* gp, RDP_EVENT* event);
++
++G_END_DECLS
++
++#endif
+diff --git a/remmina-plugins/rdp/rdp_event.c b/remmina-plugins/rdp/rdp_event.c
+index f77f5f1..a936fb1 100644
+--- a/remmina-plugins/rdp/rdp_event.c
++++ b/remmina-plugins/rdp/rdp_event.c
+@@ -461,6 +461,16 @@ static gboolean remmina_rdp_event_on_key(GtkWidget* widget, GdkEventKey* event,
+ 	return TRUE;
+ }
+ 
++static gboolean remmina_rdp_event_on_clipboard(GtkClipboard *clipboard, GdkEvent *event, RemminaProtocolWidget *gp)
++{
++	RemminaPluginRdpEvent rdp_event = { 0 };
++
++	rdp_event.type = REMMINA_RDP_EVENT_TYPE_CLIPBOARD;
++	remmina_rdp_event_event_push(gp, &rdp_event);
++
++	return TRUE;
++}
++
+ void remmina_rdp_event_init(RemminaProtocolWidget* gp)
+ {
+ 	gint n;
+@@ -470,6 +480,7 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp)
+ 	XPixmapFormatValues* pf;
+ 	XPixmapFormatValues* pfs;
+ 	rfContext* rfi;
++	GtkClipboard* clipboard;
+ 
+ 	rfi = GET_DATA(gp);
+ 	rfi->drawing_area = gtk_drawing_area_new();
+@@ -508,6 +519,14 @@ void remmina_rdp_event_init(RemminaProtocolWidget* gp)
+ 	g_signal_connect(G_OBJECT(rfi->drawing_area), "key-release-event",
+ 		G_CALLBACK(remmina_rdp_event_on_key), gp);
+ 
++	RemminaFile* remminafile = remmina_plugin_service->protocol_plugin_get_file(gp);
++	if (!remmina_plugin_service->file_get_int(remminafile, "disableclipboard", FALSE))
++	{
++		clipboard = gtk_widget_get_clipboard(rfi->drawing_area, GDK_SELECTION_CLIPBOARD);
++		g_signal_connect(clipboard, "owner-change",
++			G_CALLBACK(remmina_rdp_event_on_clipboard), gp);
++	}
++
+ 	rfi->pressed_keys = g_array_new(FALSE, TRUE, sizeof (gint));
+ 	rfi->event_queue = g_async_queue_new_full(g_free);
+ 	rfi->ui_queue = g_async_queue_new();
+diff --git a/remmina-plugins/rdp/rdp_plugin.c b/remmina-plugins/rdp/rdp_plugin.c
+index 08874e6..fd0fe08 100644
+--- a/remmina-plugins/rdp/rdp_plugin.c
++++ b/remmina-plugins/rdp/rdp_plugin.c
+@@ -24,6 +24,7 @@
+ #include "rdp_graphics.h"
+ #include "rdp_file.h"
+ #include "rdp_settings.h"
++#include "rdp_cliprdr.h"
+ 
+ #include <errno.h>
+ #include <pthread.h>
+@@ -31,6 +32,7 @@
+ #include <freerdp/freerdp.h>
+ #include <freerdp/constants.h>
+ #include <freerdp/utils/memory.h>
++#include <freerdp/plugins/cliprdr.h>
+ 
+ #define REMMINA_RDP_FEATURE_TOOL_REFRESH		1
+ #define REMMINA_RDP_FEATURE_SCALE			2
+@@ -128,6 +130,11 @@ boolean rf_check_fds(RemminaProtocolWidget* gp)
+ 				input->MouseEvent(input, event->mouse_event.flags,
+ 						event->mouse_event.x, event->mouse_event.y);
+ 				break;
++			case REMMINA_RDP_EVENT_TYPE_CLIPBOARD:
++				if (!rfi->clipboard_wait)
++					remmina_rdp_cliprdr_send_format_list_event(gp);
++				rfi->clipboard_wait = FALSE;
++				break;
+ 		}
+ 
+ 		g_free(event);
+@@ -503,6 +510,7 @@ static boolean remmina_rdp_verify_certificate(freerdp* instance, char* subject,
+ 
+ static int remmina_rdp_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size)
+ {
++	g_printf("EVENT RECEIVED -> DATA: %s\nSIZE: %d\nFLAGS: %d\n", (char*)data, size, flags);
+ 	return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
+ }
+ 
+@@ -518,6 +526,7 @@ static void remmina_rdp_main_loop(RemminaProtocolWidget* gp)
+ 	fd_set rfds_set;
+ 	fd_set wfds_set;
+ 	rfContext* rfi;
++	RDP_EVENT* event;
+ 
+ 	memset(rfds, 0, sizeof(rfds));
+ 	memset(wfds, 0, sizeof(wfds));
+@@ -591,6 +600,12 @@ static void remmina_rdp_main_loop(RemminaProtocolWidget* gp)
+ 		{
+ 			break;
+ 		}
++		else
++		{
++			event = freerdp_channels_pop_event(rfi->channels);
++			if (event)
++				remmina_handle_channel_event(gp, event);
++		}
+ 		/* check ui */
+ 		if (!rf_check_fds(gp))
+ 		{
+diff --git a/remmina-plugins/rdp/rdp_plugin.h b/remmina-plugins/rdp/rdp_plugin.h
+index a3774d9..1931384 100644
+--- a/remmina-plugins/rdp/rdp_plugin.h
++++ b/remmina-plugins/rdp/rdp_plugin.h
+@@ -133,12 +133,16 @@ struct rf_context
+ 	GArray* pressed_keys;
+ 	GAsyncQueue* event_queue;
+ 	gint event_pipe[2];
++
++	gboolean clipboard_wait;
++	uint32 requested_format;
+ };
+ 
+ typedef enum
+ {
+ 	REMMINA_RDP_EVENT_TYPE_SCANCODE,
+-	REMMINA_RDP_EVENT_TYPE_MOUSE
++	REMMINA_RDP_EVENT_TYPE_MOUSE,
++	REMMINA_RDP_EVENT_TYPE_CLIPBOARD
+ } RemminaPluginRdpEventType;
+ 
+ struct remmina_plugin_rdp_event
+-- 
+1.7.10
+
diff --git a/remmina-1.0.0-clipboard-bugfix.patch b/remmina-1.0.0-clipboard-bugfix.patch
new file mode 100644
index 0000000..c564c8e
--- /dev/null
+++ b/remmina-1.0.0-clipboard-bugfix.patch
@@ -0,0 +1,73 @@
+From 97c2af8ccc913b0850ed4a54ed6c477cfbd7b475 Mon Sep 17 00:00:00 2001
+From: Jean-Louis Dupond <jean-louis at dupond.be>
+Date: Tue, 1 May 2012 17:37:21 +0200
+Subject: [PATCH] clipboard bugfix + cleanup of memory
+
+---
+ remmina-plugins/rdp/rdp_cliprdr.c |   20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/remmina-plugins/rdp/rdp_cliprdr.c b/remmina-plugins/rdp/rdp_cliprdr.c
+index 0821ffa..b9b37ad 100644
+--- a/remmina-plugins/rdp/rdp_cliprdr.c
++++ b/remmina-plugins/rdp/rdp_cliprdr.c
+@@ -225,7 +225,7 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 
+ 	if (format == CB_FORMAT_TEXT || format == CB_FORMAT_HTML || format == CB_FORMAT_UNICODETEXT)
+ 	{
+-		lf2crlf(inbuf, size);
++		inbuf = lf2crlf(inbuf, size);
+ 		if (format == CB_FORMAT_TEXT)
+ 		{
+ 			outbuf = inbuf;
+@@ -269,6 +269,11 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 			memcpy(outbuf, data + 14, *size);
+ 		}
+ 	}
++
++	if (inbuf)
++		g_free(inbuf);
++	if (G_IS_OBJECT(image))
++		g_object_unref(image);
+ 	
+ 	if (!outbuf)
+ 		outbuf = (uint8*)"";
+@@ -288,7 +293,7 @@ void remmina_rdp_cliprdr_parse_response_event(RemminaProtocolWidget* gp, RDP_EVE
+ 	gboolean img = FALSE;
+ 	rfContext* rfi = GET_DATA(gp);
+ 	RDP_CB_DATA_RESPONSE_EVENT* data_response_event;
+-
++	GdkPixbufLoader *pixbuf;
+ 	data_response_event = (RDP_CB_DATA_RESPONSE_EVENT*) event;
+ 	data = data_response_event->data;
+ 	size = data_response_event->size;
+@@ -341,7 +346,6 @@ void remmina_rdp_cliprdr_parse_response_event(RemminaProtocolWidget* gp, RDP_EVE
+ 			stream_detach(s);
+ 			stream_free(s);
+ 		}
+-		GdkPixbufLoader *pixbuf;
+ 		pixbuf = gdk_pixbuf_loader_new();
+ 		gdk_pixbuf_loader_write(pixbuf, data, size, NULL);
+ 		image = gdk_pixbuf_loader_get_pixbuf(pixbuf);
+@@ -355,9 +359,17 @@ void remmina_rdp_cliprdr_parse_response_event(RemminaProtocolWidget* gp, RDP_EVE
+ 		if (text || img)
+ 			rfi->clipboard_wait = TRUE;
+ 		if (text)
+-			gtk_clipboard_set_text(clipboard, (gchar*)data, size);		
++		{
++			gtk_clipboard_set_text(clipboard, (gchar*)data, size);
++			gtk_clipboard_store(clipboard);
++		}
+ 		if (img)
++		{
+ 			gtk_clipboard_set_image(clipboard, image);
++			gtk_clipboard_store(clipboard);
++			gdk_pixbuf_loader_close(pixbuf, NULL);
++			g_object_unref(pixbuf);
++		}
+ 	}
+ 	THREADS_LEAVE
+ 	
+-- 
+1.7.10
+
diff --git a/remmina-1.0.0-fix-crashes-in-some-cases.patch b/remmina-1.0.0-fix-crashes-in-some-cases.patch
new file mode 100644
index 0000000..64baac0
--- /dev/null
+++ b/remmina-1.0.0-fix-crashes-in-some-cases.patch
@@ -0,0 +1,71 @@
+From 6ee2028996ee9d8802201e95f3cec56e2b307ddb Mon Sep 17 00:00:00 2001
+From: Jean-Louis Dupond <jean-louis at dupond.be>
+Date: Sat, 5 May 2012 16:54:18 +0200
+Subject: [PATCH] Fix crashes in some cases
+
+---
+ remmina-plugins/rdp/rdp_cliprdr.c |   19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/remmina-plugins/rdp/rdp_cliprdr.c b/remmina-plugins/rdp/rdp_cliprdr.c
+index d84374e..772709c 100644
+--- a/remmina-plugins/rdp/rdp_cliprdr.c
++++ b/remmina-plugins/rdp/rdp_cliprdr.c
+@@ -204,7 +204,7 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 	g_printf("GetData: Requested Format: %#X\n", format);
+ 	rfContext* rfi = GET_DATA(gp);
+ 	GtkClipboard* clipboard;
+-	uint8* inbuf = (uint8*)"";
++	uint8* inbuf = NULL;
+ 	uint8* outbuf = NULL;
+ 	GdkPixbuf *image = NULL;
+ 	
+@@ -223,10 +223,18 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 	}
+ 	THREADS_LEAVE
+ 
++	/* No data received, send nothing */
++	if (inbuf == NULL && image == NULL)
++	{
++		g_printf("NO DATA RECEIVED\n");
++		*size = 0;
++		return NULL;
++	}
++
++
+ 	if (format == CB_FORMAT_TEXT || format == CB_FORMAT_HTML || format == CB_FORMAT_UNICODETEXT)
+ 	{
+-		if (inbuf == NULL)
+-			inbuf = (uint8*)"";
++		*size = strlen((char*)inbuf);
+ 		inbuf = lf2crlf(inbuf, size);
+ 		if (format == CB_FORMAT_TEXT)
+ 		{
+@@ -258,12 +266,14 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "png", NULL, NULL);
+ 			outbuf = (uint8*) xmalloc(buffersize);
+ 			memcpy(outbuf, data, buffersize);
++			*size = buffersize;
+ 		}
+ 		if (format == CB_FORMAT_JPEG)
+ 		{
+ 			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "jpeg", NULL, NULL);
+ 			outbuf = (uint8*) xmalloc(buffersize);
+ 			memcpy(outbuf, data, buffersize);
++			*size = buffersize;
+ 		}
+ 		if (format == CB_FORMAT_DIB)
+ 		{
+@@ -276,9 +286,6 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 		g_object_unref(image);
+ 	}
+ 
+-	if (!outbuf)
+-		outbuf = (uint8*)"";
+-
+ 	return outbuf;
+ }
+ 
+-- 
+1.7.10
+
diff --git a/remmina-1.0.0-fix-memory-leak.patch b/remmina-1.0.0-fix-memory-leak.patch
new file mode 100644
index 0000000..a0aac1a
--- /dev/null
+++ b/remmina-1.0.0-fix-memory-leak.patch
@@ -0,0 +1,24 @@
+From b22778270ad05fed21797d5a5d4b782d6e273a59 Mon Sep 17 00:00:00 2001
+From: Jean-Louis Dupond <jean-louis at dupond.be>
+Date: Sat, 5 May 2012 17:15:29 +0200
+Subject: [PATCH] Fix memory leak
+
+---
+ remmina-plugins/rdp/rdp_cliprdr.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/remmina-plugins/rdp/rdp_cliprdr.c b/remmina-plugins/rdp/rdp_cliprdr.c
+index 772709c..ea8baa0 100644
+--- a/remmina-plugins/rdp/rdp_cliprdr.c
++++ b/remmina-plugins/rdp/rdp_cliprdr.c
+@@ -74,6 +74,7 @@ void remmina_rdp_cliprdr_get_target_types(uint32** dst_formats, uint16* size, Gd
+ 			image = TRUE;
+ 			matches++;
+ 		}
++		g_free(name);
+ 	}
+ 	//Only add text formats if we don't have image formats
+ 	if (!image)
+-- 
+1.7.10
+
diff --git a/remmina-1.0.0-some-more-clipboard-fixes.patch b/remmina-1.0.0-some-more-clipboard-fixes.patch
new file mode 100644
index 0000000..ad31d51
--- /dev/null
+++ b/remmina-1.0.0-some-more-clipboard-fixes.patch
@@ -0,0 +1,180 @@
+From 84327f81995b4efe56503b94216e35eb9e99f243 Mon Sep 17 00:00:00 2001
+From: Jean-Louis Dupond <jean-louis at dupond.be>
+Date: Thu, 3 May 2012 15:25:02 +0200
+Subject: [PATCH] Some more clipboard fixes
+
+---
+ remmina-plugins/rdp/rdp_cliprdr.c |   68 ++++++++++++++++++++++---------------
+ remmina-plugins/rdp/rdp_plugin.c  |    9 +++--
+ remmina-plugins/rdp/rdp_plugin.h  |    2 +-
+ 3 files changed, 48 insertions(+), 31 deletions(-)
+
+diff --git a/remmina-plugins/rdp/rdp_cliprdr.c b/remmina-plugins/rdp/rdp_cliprdr.c
+index b9b37ad..1424ac9 100644
+--- a/remmina-plugins/rdp/rdp_cliprdr.c
++++ b/remmina-plugins/rdp/rdp_cliprdr.c
+@@ -204,7 +204,7 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 	g_printf("GetData: Requested Format: %#X\n", format);
+ 	rfContext* rfi = GET_DATA(gp);
+ 	GtkClipboard* clipboard;
+-	uint8* inbuf = NULL;
++	uint8* inbuf = (uint8*)"";
+ 	uint8* outbuf = NULL;
+ 	GdkPixbuf *image = NULL;
+ 	
+@@ -225,6 +225,8 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 
+ 	if (format == CB_FORMAT_TEXT || format == CB_FORMAT_HTML || format == CB_FORMAT_UNICODETEXT)
+ 	{
++		if (inbuf == NULL)
++			inbuf = (uint8*)"";
+ 		inbuf = lf2crlf(inbuf, size);
+ 		if (format == CB_FORMAT_TEXT)
+ 		{
+@@ -243,6 +245,7 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 			uniconv = freerdp_uniconv_new();
+ 			outbuf = (uint8*) freerdp_uniconv_out(uniconv, (char*) inbuf, &out_size);
+ 			freerdp_uniconv_free(uniconv);
++			g_free(inbuf);
+ 			*size = out_size + 2;
+ 		}
+ 	}
+@@ -253,11 +256,13 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 		if (format == CB_FORMAT_PNG)
+ 		{
+ 			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "png", NULL, NULL);
++			outbuf = (uint8*) xmalloc(buffersize);
+ 			memcpy(outbuf, data, buffersize);
+ 		}
+ 		if (format == CB_FORMAT_JPEG)
+ 		{
+ 			gdk_pixbuf_save_to_buffer(image, &data, &buffersize, "jpeg", NULL, NULL);
++			outbuf = (uint8*) xmalloc(buffersize);
+ 			memcpy(outbuf, data, buffersize);
+ 		}
+ 		if (format == CB_FORMAT_DIB)
+@@ -268,13 +273,9 @@ uint8* remmina_rdp_cliprdr_get_data(RemminaProtocolWidget* gp, uint32 format, in
+ 			outbuf = (uint8*) xmalloc(*size);
+ 			memcpy(outbuf, data + 14, *size);
+ 		}
++		g_object_unref(image);
+ 	}
+ 
+-	if (inbuf)
+-		g_free(inbuf);
+-	if (G_IS_OBJECT(image))
+-		g_object_unref(image);
+-	
+ 	if (!outbuf)
+ 		outbuf = (uint8*)"";
+ 
+@@ -357,7 +358,10 @@ void remmina_rdp_cliprdr_parse_response_event(RemminaProtocolWidget* gp, RDP_EVE
+ 	if (clipboard)
+ 	{
+ 		if (text || img)
+-			rfi->clipboard_wait = TRUE;
++		{
++			rfi->clipboard_wait = 2;
++			g_printf("Setting Clipboard Wait\n");
++		}
+ 		if (text)
+ 		{
+ 			gtk_clipboard_set_text(clipboard, (gchar*)data, size);
+@@ -404,31 +408,39 @@ void remmina_handle_channel_event(RemminaProtocolWidget* gp, RDP_EVENT* event)
+ 				for (i = 0; i < format_list_event->num_formats; i++)
+ 				{
+ 					g_printf("Format: 0x%X\n", format_list_event->formats[i]);
+-					if (format_list_event->formats[i] == CB_FORMAT_UNICODETEXT)
+-					{
+-						format = CB_FORMAT_UNICODETEXT;
+-						break;
+-					}
+-					if (format_list_event->formats[i] == CB_FORMAT_DIB)
+-					{
+-						format = CB_FORMAT_DIB;
+-						break;
+-					}
+-					if (format_list_event->formats[i] == CB_FORMAT_JPEG)
++				}
++
++				for (i = 0; i < format_list_event->num_formats; i++)
++				{
++					g_printf("Format: 0x%X\n", format_list_event->formats[i]);
++					if (format_list_event->formats[i] > format)
+ 					{
+-						format = CB_FORMAT_JPEG;
+-						break;
++						g_printf("Format 0x%X is bigger!\n", format_list_event->formats[i]);
++						if (format_list_event->formats[i] == CB_FORMAT_UNICODETEXT)
++						{
++							format = CB_FORMAT_UNICODETEXT;
++						}
++						if (format_list_event->formats[i] == CB_FORMAT_DIB)
++						{
++							format = CB_FORMAT_DIB;
++						}
++						if (format_list_event->formats[i] == CB_FORMAT_JPEG)
++						{
++							format = CB_FORMAT_JPEG;
++						}
++						if (format_list_event->formats[i] == CB_FORMAT_PNG)
++						{
++							format = CB_FORMAT_PNG;
++						}
++						if (format_list_event->formats[i] == CB_FORMAT_TEXT)
++						{
++							format = CB_FORMAT_TEXT;
++						}
+ 					}
+-					if (format_list_event->formats[i] == CB_FORMAT_PNG)
++					else
+ 					{
+-						format = CB_FORMAT_PNG;
+-						break;
++						g_printf("Format 0x%X is smaller!\n", format_list_event->formats[i]);
+ 					}
+-					if (format_list_event->formats[i] == CB_FORMAT_TEXT)
+-					{
+-						format = CB_FORMAT_TEXT;
+-						break;
+-					}				
+ 				}
+ 				rfi->requested_format = format;
+ 				
+diff --git a/remmina-plugins/rdp/rdp_plugin.c b/remmina-plugins/rdp/rdp_plugin.c
+index fd0fe08..3c7fc0a 100644
+--- a/remmina-plugins/rdp/rdp_plugin.c
++++ b/remmina-plugins/rdp/rdp_plugin.c
+@@ -131,9 +131,14 @@ boolean rf_check_fds(RemminaProtocolWidget* gp)
+ 						event->mouse_event.x, event->mouse_event.y);
+ 				break;
+ 			case REMMINA_RDP_EVENT_TYPE_CLIPBOARD:
+-				if (!rfi->clipboard_wait)
++				if (rfi->clipboard_wait <= 0)
++				{
+ 					remmina_rdp_cliprdr_send_format_list_event(gp);
+-				rfi->clipboard_wait = FALSE;
++					g_printf("Clipboard Wait ON\n");
++					rfi->clipboard_wait = 0;
++				}
++				g_printf("Setting Clipboard Wait To FALSE\n");
++				rfi->clipboard_wait--;
+ 				break;
+ 		}
+ 
+diff --git a/remmina-plugins/rdp/rdp_plugin.h b/remmina-plugins/rdp/rdp_plugin.h
+index 1931384..ff66906 100644
+--- a/remmina-plugins/rdp/rdp_plugin.h
++++ b/remmina-plugins/rdp/rdp_plugin.h
+@@ -134,7 +134,7 @@ struct rf_context
+ 	GAsyncQueue* event_queue;
+ 	gint event_pipe[2];
+ 
+-	gboolean clipboard_wait;
++	gint clipboard_wait;
+ 	uint32 requested_format;
+ };
+ 
+-- 
+1.7.10
+
diff --git a/remmina.spec b/remmina.spec
index 1c13271..2e6c8a8 100644
--- a/remmina.spec
+++ b/remmina.spec
@@ -2,7 +2,7 @@
 
 Name:           remmina
 Version:        1.0.0
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Remote Desktop Client
 
 Group:          Applications/Internet
@@ -17,6 +17,19 @@ Patch0:         remmina-1.0.0-fix-library-name.patch
 # https://github.com/FreeRDP/Remmina/commit/13f20367
 Patch1:         remmina-1.0.0-linker-error.patch
 
+# The following 3 patches are needed to add clipboard support (#818155)
+# https://github.com/FreeRDP/Remmina/commit/3ebdd6e7
+Patch2:         remmina-1.0.0-add-clipboard-support.patch
+# https://github.com/FreeRDP/Remmina/commit/97c2af8c
+Patch3:         remmina-1.0.0-clipboard-bugfix.patch
+# https://github.com/FreeRDP/Remmina/commit/84327f81
+Patch4:         remmina-1.0.0-some-more-clipboard-fixes.patch
+
+# https://github.com/FreeRDP/Remmina/commit/6ee20289
+Patch5:        remmina-1.0.0-fix-crashes-in-some-cases.patch
+# https://github.com/FreeRDP/Remmina/commit/b2277827
+Patch6:        remmina-1.0.0-fix-memory-leak.patch
+
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 BuildRequires:  gtk3-devel
@@ -180,6 +193,13 @@ client.
 %patch0 -p1 -b .fix-library-name
 %patch1 -p1 -b .linker-error
 
+%patch2 -p1 -b .add-clipboard-support
+%patch3 -p1 -b .clipboard-bugfix
+%patch4 -p1 -b .some-more-clipboard-fixes
+
+%patch5  -p1 -b .fix-crashes-in-some-cases
+%patch6  -p1 -b .fix-memory-leak
+
 # Don't hardcode libdir
 sed -i "s,/lib/remmina/plugins,/%{_lib}/remmina/plugins,g" CMakeLists.txt
 
@@ -310,6 +330,10 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 
 
 %changelog
+* Fri Jun 01 2012 Christoph Wickert <cwickert at fedoraproject.org> - 1.0.0-2
+- Add clipboard support (#818155)
+- Fix a memory leak and a crash
+
 * Sun Apr 22 2012 Christoph Wickert <cwickert at fedoraproject.org> - 1.0.0-1
 - Update to 1.0.0
 - Plugins are now part of this package (again)


More information about the scm-commits mailing list