Commit 5caf0121 authored by Giovanni Panozzo's avatar Giovanni Panozzo

Plugin assisted screenshot

parent bb0aa93a
......@@ -799,7 +799,8 @@ static RemminaProtocolPlugin remmina_plugin_nx =
remmina_plugin_nx_close_connection, // Plugin close connection
remmina_plugin_nx_query_feature, // Query for available features
remmina_plugin_nx_call_feature, // Call a feature
NULL // Send a keystroke
NULL, // Send a keystroke
NULL // Screenshot
};
G_MODULE_EXPORT gboolean
......
......@@ -1077,6 +1077,3 @@ int remmina_rdp_event_queue_ui(RemminaProtocolWidget* gp, RemminaPluginRdpUiObje
pthread_setcanceltype(oldcanceltype, NULL);
return rc;
}
......@@ -1230,6 +1230,40 @@ static void remmina_rdp_keystroke(RemminaProtocolWidget *gp, const guint keystro
return;
}
static gboolean remmina_rdp_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
{
rfContext* rfi = GET_PLUGIN_DATA(gp);
rdpGdi* gdi;
size_t szmem;
if (!rfi)
return FALSE;
/* ToDo: we should lock freerdp subthread to update rfi->primary_buffer, rfi->gdi and w/h,
* from here to memcpy, but... how ? */
gdi = ((rdpContext *)rfi)->gdi;
szmem = gdi->width * gdi->height * rfi->hdc->bytesPerPixel;
remmina_plugin_service->log_printf("[RDP] allocating %zu bytes for a full screenshot\n", szmem);
rpsd->buffer = malloc(szmem);
if (!rpsd->buffer)
{
remmina_plugin_service->log_printf("[RDP] unable to allocate %zu bytes for a full screenshot\n", szmem);
return FALSE;
}
rpsd->width = gdi->width;
rpsd->height = gdi->height;
rpsd->bitsPerPixel = rfi->hdc->bitsPerPixel;
rpsd->bytesPerPixel = rfi->hdc->bytesPerPixel;
memcpy(rpsd->buffer, rfi->primary_buffer, szmem);
/* Returning TRUE instruct also the caller to deallocate rpsd->buffer */
return TRUE;
}
/* Array of key/value pairs for color depths */
static gpointer colordepth_list[] =
{
......@@ -1355,7 +1389,8 @@ static RemminaProtocolPlugin remmina_rdp =
remmina_rdp_close_connection, // Plugin close connection
remmina_rdp_query_feature, // Query for available features
remmina_rdp_call_feature, // Call a feature
remmina_rdp_keystroke // Send a keystroke
remmina_rdp_keystroke, // Send a keystroke
remmina_rdp_get_screenshot // Screenshot
};
/* File plugin definition and features */
......
......@@ -2088,7 +2088,8 @@ static RemminaProtocolPlugin remmina_plugin_vnci =
remmina_plugin_vnc_close_connection, // Plugin close connection
remmina_plugin_vnc_query_feature, // Query for available features
remmina_plugin_vnc_call_feature, // Call a feature
remmina_plugin_vnc_keystroke // Send a keystroke
remmina_plugin_vnc_keystroke, // Send a keystroke
NULL // No screenshot support available
};
G_MODULE_EXPORT gboolean
......
/*
* Remmina - The GTK+ Remote Desktop Client
* Copyright (C) 2010 Vic Lee
* Copyright (C) 2010 Vic Lee
* Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
*
* This program is free software; you can redistribute it and/or modify
......@@ -15,7 +15,7 @@
*
* 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., 51 Franklin Street, Fifth Floor,
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
......@@ -422,7 +422,8 @@ static RemminaProtocolPlugin remmina_plugin_xdmcp =
remmina_plugin_xdmcp_close_connection, // Plugin close connection
remmina_plugin_xdmcp_query_feature, // Query for available features
remmina_plugin_xdmcp_call_feature, // Call a feature
NULL // Send a keystroke
NULL, // Send a keystroke
NULL // Screenshot
};
G_MODULE_EXPORT gboolean
......
......@@ -81,6 +81,7 @@ typedef struct _RemminaProtocolPlugin
gboolean (* query_feature) (RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature);
void (* call_feature) (RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature);
void (* send_keystrokes) (RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen);
gboolean (* get_plugin_screenshot)(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd);
} RemminaProtocolPlugin;
typedef struct _RemminaEntryPlugin
......
/*
* Remmina - The GTK+ Remote Desktop Client
* Copyright (C) 2010 Vic Lee
* Copyright (C) 2010 Vic Lee
* Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
*
* This program is free software; you can redistribute it and/or modify
......@@ -15,7 +15,7 @@
*
* 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., 51 Franklin Street, Fifth Floor,
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
......@@ -61,6 +61,15 @@ typedef struct _RemminaProtocolFeature
gpointer opt3;
} RemminaProtocolFeature;
typedef struct _RemminaPluginScreenshotData {
unsigned char* buffer;
int bitsPerPixel;
int bytesPerPixel;
int width;
int height;
} RemminaPluginScreenshotData;
typedef struct _RemminaProtocolWidgetClass RemminaProtocolWidgetClass;
typedef struct _RemminaProtocolWidget RemminaProtocolWidget;
typedef gpointer RemminaTunnelInitFunc;
......
......@@ -54,6 +54,7 @@
#include "remmina_public.h"
#include "remmina_scrolled_viewport.h"
#include "remmina_widget_pool.h"
#include "remmina_log.h"
#include "remmina/remmina_trace_calls.h"
G_DEFINE_TYPE( RemminaConnectionWindow, remmina_connection_window, GTK_TYPE_WINDOW)
......@@ -1563,6 +1564,11 @@ static void remmina_connection_holder_toolbar_screenshot(GtkWidget* widget, Remm
gchar* pngdate;
GtkWidget* dialog;
RemminaProtocolWidget *gp;
RemminaPluginScreenshotData rpsd;
cairo_surface_t *srcsurface;
cairo_format_t cairo_format;
cairo_surface_t *surface;
int stride;
GDateTime *date = g_date_time_new_now_utc ();
......@@ -1571,26 +1577,69 @@ static void remmina_connection_holder_toolbar_screenshot(GtkWidget* widget, Remm
DECLARE_CNNOBJ
gp = REMMINA_PROTOCOL_WIDGET(cnnobj->proto);
//Get the screenshot.
active_window = gtk_widget_get_window(GTK_WIDGET(gp));
//width = gdk_window_get_width
(gtk_widget_get_window(GTK_WIDGET(cnnhld->cnnwin)));
width = gdk_window_get_width (active_window);
//height = gdk_window_get_height
(gtk_widget_get_window(GTK_WIDGET(cnnhld->cnnwin)));
height = gdk_window_get_height (active_window);
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
screenshot = gdk_pixbuf_get_from_window (active_window, 0, 0, width, height);
if (screenshot == NULL)
g_print("gdk_pixbuf_get_from_window failed\n");
//Prepare the cairo surface.
cr = cairo_create(surface);
// Ask the plugin if it can give us a screenshot
if (remmina_protocol_widget_plugin_screenshot(gp, &rpsd)) {
// Good, we have a screenshot from the plugin !
remmina_log_printf("Screenshot from plugin: w=%d h=%d bpp=%d bytespp=%d\n",
rpsd.width, rpsd.height, rpsd.bitsPerPixel, rpsd.bytesPerPixel);
width = rpsd.width;
height = rpsd.height;
if (rpsd.bitsPerPixel == 32)
cairo_format = CAIRO_FORMAT_ARGB32;
else
cairo_format = CAIRO_FORMAT_RGB16_565;
stride = cairo_format_stride_for_width(cairo_format, width);
srcsurface = cairo_image_surface_create_for_data(rpsd.buffer, cairo_format, width, height, stride);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
cr = cairo_create(surface);
cairo_set_source_surface(cr, srcsurface, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_surface_destroy(srcsurface);
free(rpsd.buffer);
} else {
// The plugin is not releasing us a screenshot, just try to catch one via GTK
/* Warn the user if image is distorted */
if (cnnobj->plugin_can_scale &&
remmina_protocol_widget_get_scale(gp)) {
dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
_("Warning: screenshot is scaled or distorted. Disable scaling to have better screenshot."));
g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_widget_show(dialog);
}
// Get the screenshot.
active_window = gtk_widget_get_window(GTK_WIDGET(gp));
// width = gdk_window_get_width(gtk_widget_get_window(GTK_WIDGET(cnnhld->cnnwin)));
width = gdk_window_get_width (active_window);
// height = gdk_window_get_height(gtk_widget_get_window(GTK_WIDGET(cnnhld->cnnwin)));
height = gdk_window_get_height (active_window);
screenshot = gdk_pixbuf_get_from_window (active_window, 0, 0, width, height);
if (screenshot == NULL)
g_print("gdk_pixbuf_get_from_window failed\n");
// Prepare the destination cairo surface.
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
cr = cairo_create(surface);
// Copy the source pixbuf to the surface and paint it.
gdk_cairo_set_source_pixbuf(cr, screenshot, 0, 0);
cairo_paint(cr);
//Copy the pixbuf to the surface and paint it.
gdk_cairo_set_source_pixbuf(cr, screenshot, 0, 0);
cairo_paint(cr);
// Deallocate screenshot pixbuf
// g_object_unref(screenshot);
}
remminafile = remmina_file_get_filename(cnnobj->remmina_file);
//imagedir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
......@@ -1614,14 +1663,6 @@ static void remmina_connection_holder_toolbar_screenshot(GtkWidget* widget, Remm
cairo_destroy(cr);
cairo_surface_destroy(surface);
/* Warn the user if image is distorted */
if (cnnobj->plugin_can_scale &&
remmina_protocol_widget_get_scale(gp)) {
dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
_("Warning: screenshot is scaled or distorted. Disable scaling to have better screenshot."));
g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL);
gtk_widget_show(dialog);
}
}
......
......@@ -51,6 +51,7 @@
#include "remmina_protocol_widget.h"
#include "remmina_public.h"
#include "remmina_ssh.h"
#include "remmina_log.h"
#include "remmina/remmina_trace_calls.h"
struct _RemminaProtocolWidgetPriv
......@@ -437,6 +438,17 @@ void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget* gp, GtkMenuI
return;
}
gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget* gp, RemminaPluginScreenshotData *rpsd)
{
if (!gp->priv->plugin->get_plugin_screenshot) {
remmina_log_printf("plugin screenshot function is not implemented\n");
return FALSE;
}
return gp->priv->plugin->get_plugin_screenshot(gp, rpsd);
}
void remmina_protocol_widget_emit_signal(RemminaProtocolWidget* gp, const gchar* signal_name)
{
......
......@@ -148,6 +148,8 @@ void remmina_protocol_widget_send_keys_signals(GtkWidget *widget, const guint *k
gboolean remmina_protocol_widget_plugin_receives_keystrokes(RemminaProtocolWidget* gp);
/* Send to the plugin some keystrokes */
void remmina_protocol_widget_send_keystrokes(RemminaProtocolWidget* gp, GtkMenuItem *widget);
/* Take screenshot of plugin */
gboolean remmina_protocol_widget_plugin_screenshot(RemminaProtocolWidget* gp, RemminaPluginScreenshotData *rpsd);
G_END_DECLS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment