[vinagre] Allow scaling of RDP sessions



commit 66f91ed8a5c07d17f44990a8f5fb7647df04f60d
Author: Marek Kasik <mkasik redhat com>
Date:   Fri Sep 4 16:25:54 2015 +0200

    Allow scaling of RDP sessions
    
    Add ability to scale RDP sessions using scaling functionality of cairo library.
    Session is placed in the center of the window as in other plugins.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=753766

 Makefile.am                          |    2 +
 plugins/rdp/vinagre-rdp-connection.c |  121 ++++++++++++++++++-
 plugins/rdp/vinagre-rdp-connection.h |    6 +-
 plugins/rdp/vinagre-rdp-plugin.c     |   26 +++-
 plugins/rdp/vinagre-rdp-tab.c        |  226 ++++++++++++++++++++++++++++++++-
 5 files changed, 364 insertions(+), 17 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 09ff61e..6c1ba2d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -153,6 +153,8 @@ vinagre_vinagre_SOURCES += \
        plugins/rdp/vinagre-rdp-plugin.c \
        plugins/rdp/vinagre-rdp-connection.c \
        plugins/rdp/vinagre-rdp-tab.c
+
+vinagre_vinagre_LDADD += -lm
 endif
 
 if VINAGRE_ENABLE_SPICE
diff --git a/plugins/rdp/vinagre-rdp-connection.c b/plugins/rdp/vinagre-rdp-connection.c
index 99182c7..c5f6ed1 100644
--- a/plugins/rdp/vinagre-rdp-connection.c
+++ b/plugins/rdp/vinagre-rdp-connection.c
@@ -23,9 +23,17 @@
 #include <vinagre/vinagre-cache-prefs.h>
 #include "vinagre-rdp-connection.h"
 
+#include "vinagre-vala.h"
+
 struct _VinagreRdpConnectionPrivate
 {
-  gint dummy;
+  gboolean scaling;
+};
+
+enum
+{
+  PROP_0,
+  PROP_SCALING,
 };
 
 #define VINAGRE_RDP_CONNECTION_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), VINAGRE_TYPE_RDP_CONNECTION, 
VinagreRdpConnectionPrivate))
@@ -44,21 +52,83 @@ vinagre_rdp_connection_constructed (GObject *object)
 }
 
 static void
+vinagre_rdp_connection_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+  VinagreRdpConnection *conn;
+
+  g_return_if_fail (VINAGRE_IS_RDP_CONNECTION (object));
+
+  conn = VINAGRE_RDP_CONNECTION (object);
+
+  switch (prop_id)
+    {
+      case PROP_SCALING:
+        vinagre_rdp_connection_set_scaling (conn, g_value_get_boolean (value));
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+vinagre_rdp_connection_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+  VinagreRdpConnection *conn;
+
+  g_return_if_fail (VINAGRE_IS_RDP_CONNECTION (object));
+
+  conn = VINAGRE_RDP_CONNECTION (object);
+
+  switch (prop_id)
+    {
+      case PROP_SCALING:
+        g_value_set_boolean (value, conn->priv->scaling);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
 rdp_fill_writer (VinagreConnection *conn, xmlTextWriter *writer)
 {
+  VinagreRdpConnection *rdp_conn = VINAGRE_RDP_CONNECTION (conn);
   VINAGRE_CONNECTION_CLASS (vinagre_rdp_connection_parent_class)->impl_fill_writer (conn, writer);
+
+  xmlTextWriterWriteFormatElement (writer, BAD_CAST "scaling", "%d", rdp_conn->priv->scaling);
 }
 
 static void
 rdp_parse_item (VinagreConnection *conn, xmlNode *root)
 {
+  xmlNode *curr;
+  xmlChar *s_value;
+  VinagreRdpConnection *rdp_conn = VINAGRE_RDP_CONNECTION (conn);
+
   VINAGRE_CONNECTION_CLASS (vinagre_rdp_connection_parent_class)->impl_parse_item (conn, root);
+
+  for (curr = root->children; curr; curr = curr->next)
+    {
+      s_value = xmlNodeGetContent (curr);
+
+      if (!xmlStrcmp(curr->name, BAD_CAST "scaling"))
+        {
+          vinagre_rdp_connection_set_scaling (rdp_conn, vinagre_utils_parse_boolean ((const gchar *) 
s_value));
+        }
+
+      xmlFree (s_value);
+    }
 }
 
 static void
 rdp_parse_options_widget (VinagreConnection *conn, GtkWidget *widget)
 {
-  GtkWidget *u_entry, *spin_button;
+  GtkWidget *u_entry, *spin_button, *scaling_button;
+  gboolean   scaling;
   guint      width, height;
 
   u_entry = g_object_get_data (G_OBJECT (widget), "username_entry");
@@ -101,6 +171,22 @@ rdp_parse_options_widget (VinagreConnection *conn, GtkWidget *widget)
   vinagre_cache_prefs_set_integer  ("rdp-connection", "height", height);
 
   vinagre_connection_set_height (conn, height);
+
+
+  scaling_button = g_object_get_data (G_OBJECT (widget), "scaling");
+  if (!scaling_button)
+    {
+      g_warning ("Wrong widget passed to rdp_parse_options_widget()");
+      return;
+    }
+
+  scaling = (gboolean) gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scaling_button));
+
+  vinagre_cache_prefs_set_boolean ("rdp-connection", "scaling", scaling);
+
+  g_object_set (conn,
+                "scaling", scaling,
+                NULL);
 }
 
 static void
@@ -111,11 +197,24 @@ vinagre_rdp_connection_class_init (VinagreRdpConnectionClass *klass)
 
   g_type_class_add_private (klass, sizeof (VinagreRdpConnectionPrivate));
 
+  object_class->set_property = vinagre_rdp_connection_set_property;
+  object_class->get_property = vinagre_rdp_connection_get_property;
   object_class->constructed  = vinagre_rdp_connection_constructed;
 
   parent_class->impl_fill_writer = rdp_fill_writer;
   parent_class->impl_parse_item  = rdp_parse_item;
   parent_class->impl_parse_options_widget = rdp_parse_options_widget;
+
+  g_object_class_install_property (object_class,
+                                   PROP_SCALING,
+                                   g_param_spec_boolean ("scaling",
+                                                         "Use scaling",
+                                                         "Whether to use scaling on this connection",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+
 }
 
 VinagreConnection *
@@ -124,4 +223,22 @@ vinagre_rdp_connection_new (void)
   return VINAGRE_CONNECTION (g_object_new (VINAGRE_TYPE_RDP_CONNECTION, NULL));
 }
 
+void
+vinagre_rdp_connection_set_scaling (VinagreRdpConnection *conn,
+                                    gboolean              scaling)
+{
+  g_return_if_fail (VINAGRE_IS_RDP_CONNECTION (conn));
+
+  conn->priv->scaling = scaling;
+}
+
+gboolean
+vinagre_rdp_connection_get_scaling (VinagreRdpConnection *conn)
+{
+  g_return_val_if_fail (VINAGRE_IS_RDP_CONNECTION (conn), FALSE);
+
+  return conn->priv->scaling;
+}
+
+
 /* vim: set ts=8: */
diff --git a/plugins/rdp/vinagre-rdp-connection.h b/plugins/rdp/vinagre-rdp-connection.h
index b9e48be..b96fb1b 100644
--- a/plugins/rdp/vinagre-rdp-connection.h
+++ b/plugins/rdp/vinagre-rdp-connection.h
@@ -51,7 +51,11 @@ struct _VinagreRdpConnection
 
 GType vinagre_rdp_connection_get_type (void) G_GNUC_CONST;
 
-VinagreConnection*  vinagre_rdp_connection_new (void);
+VinagreConnection*  vinagre_rdp_connection_new         (void);
+
+gboolean            vinagre_rdp_connection_get_scaling (VinagreRdpConnection *conn);
+void                vinagre_rdp_connection_set_scaling (VinagreRdpConnection *conn,
+                                                        gboolean              scaling);
 
 G_END_DECLS
 
diff --git a/plugins/rdp/vinagre-rdp-plugin.c b/plugins/rdp/vinagre-rdp-plugin.c
index 3929065..f41da37 100644
--- a/plugins/rdp/vinagre-rdp-plugin.c
+++ b/plugins/rdp/vinagre-rdp-plugin.c
@@ -100,7 +100,7 @@ vinagre_rdp_plugin_init (VinagreRdpPlugin *plugin)
 static GtkWidget *
 impl_get_connect_widget (VinagreProtocol *plugin, VinagreConnection *conn)
 {
-  GtkWidget *grid, *label, *u_entry, *spin_button;
+  GtkWidget *grid, *label, *u_entry, *spin_button, *check;
   gchar     *str;
   gint       width, height;
 
@@ -115,16 +115,28 @@ impl_get_connect_widget (VinagreProtocol *plugin, VinagreConnection *conn)
   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
   gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
 
+
+  /* Scaling check button */
+  check = gtk_check_button_new_with_mnemonic (_("_Scaling"));
+  g_object_set_data (G_OBJECT (grid), "scaling", check);
+  gtk_widget_set_margin_left (check, 12);
+  gtk_grid_attach (GTK_GRID (grid), check, 0, 1, 1, 1);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check),
+                                VINAGRE_IS_CONNECTION (conn) ?
+                                vinagre_rdp_connection_get_scaling (VINAGRE_RDP_CONNECTION (conn)) :
+                                vinagre_cache_prefs_get_boolean ("rdp-connection", "scaling", FALSE));
+
+
   label = gtk_label_new_with_mnemonic (_("_Username:"));
   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
   gtk_widget_set_margin_left (label, 12);
 
   u_entry = gtk_entry_new ();
   /* Translators: This is the tooltip for the username field in a RDP connection */
   gtk_widget_set_tooltip_text (u_entry, _("Optional. If blank, your username will be used. Also, it can be 
supplied in the Host field above, in the form username hostname "));
   g_object_set_data (G_OBJECT (grid), "username_entry", u_entry);
-  gtk_grid_attach (GTK_GRID (grid), u_entry, 1, 1, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), u_entry, 1, 2, 1, 1);
   gtk_label_set_mnemonic_widget (GTK_LABEL (label), u_entry);
   str = g_strdup (VINAGRE_IS_CONNECTION (conn) ?
                  vinagre_connection_get_username (conn) :
@@ -137,7 +149,7 @@ impl_get_connect_widget (VinagreProtocol *plugin, VinagreConnection *conn)
   /* Host width */
   label = gtk_label_new_with_mnemonic (_("_Width:"));
   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
   gtk_widget_set_margin_left (label, 12);
 
   spin_button = gtk_spin_button_new_with_range (MIN_SIZE, MAX_SIZE, 1);
@@ -145,7 +157,7 @@ impl_get_connect_widget (VinagreProtocol *plugin, VinagreConnection *conn)
   gtk_widget_set_tooltip_text (spin_button, _("Set width of the remote desktop"));
   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin_button), DEFAULT_WIDTH);
   g_object_set_data (G_OBJECT (grid), "width_spin_button", spin_button);
-  gtk_grid_attach (GTK_GRID (grid), spin_button, 1, 2, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), spin_button, 1, 3, 1, 1);
   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
   width = VINAGRE_IS_CONNECTION (conn) ?
           vinagre_connection_get_width (conn) :
@@ -157,7 +169,7 @@ impl_get_connect_widget (VinagreProtocol *plugin, VinagreConnection *conn)
   /* Host height */
   label = gtk_label_new_with_mnemonic (_("_Height:"));
   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), label, 0, 4, 1, 1);
   gtk_widget_set_margin_left (label, 12);
 
   spin_button = gtk_spin_button_new_with_range (MIN_SIZE, MAX_SIZE, 1);
@@ -165,7 +177,7 @@ impl_get_connect_widget (VinagreProtocol *plugin, VinagreConnection *conn)
   gtk_widget_set_tooltip_text (spin_button, _("Set height of the remote desktop"));
   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin_button), DEFAULT_HEIGHT);
   g_object_set_data (G_OBJECT (grid), "height_spin_button", spin_button);
-  gtk_grid_attach (GTK_GRID (grid), spin_button, 1, 3, 1, 1);
+  gtk_grid_attach (GTK_GRID (grid), spin_button, 1, 4, 1, 1);
   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
   height = VINAGRE_IS_CONNECTION (conn) ?
            vinagre_connection_get_height (conn) :
diff --git a/plugins/rdp/vinagre-rdp-tab.c b/plugins/rdp/vinagre-rdp-tab.c
index 1074a63..6900864 100644
--- a/plugins/rdp/vinagre-rdp-tab.c
+++ b/plugins/rdp/vinagre-rdp-tab.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <glib/gi18n.h>
 #include <gdk/gdkkeysyms.h>
+#include <math.h>
 #include <freerdp/api.h>
 #include <freerdp/types.h>
 #include <freerdp/freerdp.h>
@@ -62,11 +63,23 @@ struct _VinagreRdpTabPrivate
   guint            key_press_handler_id;
   guint            key_release_handler_id;
   guint            motion_notify_handler_id;
+
+  GSList          *connected_actions;
+  GtkWidget       *scaling_button;
+  GtkAction       *scaling_action;
+  gboolean         scaling;
+  double           scale;
+  double           offset_x, offset_y;
 };
 
 G_DEFINE_TYPE (VinagreRdpTab, vinagre_rdp_tab, VINAGRE_TYPE_TAB)
 
 static void open_freerdp (VinagreRdpTab *rdp_tab);
+static void setup_toolbar (VinagreRdpTab *rdp_tab);
+static void vinagre_rdp_tab_set_scaling (VinagreRdpTab *tab,
+                                         gboolean       scaling);
+static void scaling_button_clicked (GtkToggleToolButton *button,
+                                    VinagreRdpTab       *rdp_tab);
 
 struct frdp_context
 {
@@ -128,12 +141,42 @@ free_frdpEvent (gpointer event,
 }
 
 static void
+view_scaling_cb (GtkAction     *action,
+                 VinagreRdpTab *rdp_tab)
+{
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  gboolean              scaling;
+
+  scaling = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+
+  vinagre_rdp_tab_set_scaling (rdp_tab, scaling);
+
+  g_signal_handlers_block_by_func (priv->scaling_button, scaling_button_clicked, rdp_tab);
+  gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (priv->scaling_button), scaling);
+  g_signal_handlers_unblock_by_func (priv->scaling_button, scaling_button_clicked, rdp_tab);
+}
+
+const static GSList *
+rdp_get_connected_actions (VinagreTab *tab)
+{
+  VinagreRdpTab *rdp_tab = VINAGRE_RDP_TAB (tab);
+
+  return rdp_tab->priv->connected_actions;
+}
+
+static void
 vinagre_rdp_tab_dispose (GObject *object)
 {
   VinagreRdpTab        *rdp_tab = VINAGRE_RDP_TAB (object);
   VinagreRdpTabPrivate *priv = rdp_tab->priv;
   GtkWindow            *window = GTK_WINDOW (vinagre_tab_get_window (VINAGRE_TAB (rdp_tab)));
 
+  if (priv->connected_actions)
+    {
+      vinagre_tab_free_actions (priv->connected_actions);
+      priv->connected_actions = NULL;
+    }
+
   if (priv->freerdp_session)
     {
       gdi_free (priv->freerdp_session);
@@ -195,6 +238,7 @@ vinagre_rdp_tab_constructed (GObject *object)
   if (G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->constructed)
     G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->constructed (object);
 
+  setup_toolbar (rdp_tab);
   open_freerdp (rdp_tab);
 }
 
@@ -208,6 +252,7 @@ vinagre_rdp_tab_class_init (VinagreRdpTabClass *klass)
   object_class->dispose = vinagre_rdp_tab_dispose;
 
   tab_class->impl_get_tooltip = rdp_tab_get_tooltip;
+  tab_class->impl_get_connected_actions = rdp_get_connected_actions;
 
   g_type_class_add_private (object_class, sizeof (VinagreRdpTabPrivate));
 }
@@ -220,12 +265,110 @@ idle_close (VinagreTab *tab)
   return FALSE;
 }
 
+static GSList *
+create_connected_actions (VinagreRdpTab *tab)
+{
+  GSList *list = NULL;
+  VinagreTabUiAction *action;
+
+  /* View->Scaling */
+  action = g_slice_new (VinagreTabUiAction);
+  action->paths = g_new (gchar *, 3);
+  action->paths[0] = g_strdup ("/MenuBar/ViewMenu");
+  action->paths[1] = g_strdup ("/ToolBar");
+  action->paths[2] = NULL;
+  action->action = GTK_ACTION (gtk_toggle_action_new ("RDPViewScaling",
+                                                 _("S_caling"),
+                                                 _("Fit the remote screen into the current window size"),
+                                                 "zoom-fit-best"));
+  gtk_action_set_icon_name (action->action, "zoom-fit-best");
+  g_signal_connect (action->action, "activate", G_CALLBACK (view_scaling_cb), tab);
+  list = g_slist_append (list, action);
+  tab->priv->scaling_action = action->action;
+
+  return list;
+}
+
+static void
+scaling_button_clicked (GtkToggleToolButton *button,
+                        VinagreRdpTab       *rdp_tab)
+{
+  vinagre_rdp_tab_set_scaling (rdp_tab,
+                               gtk_toggle_tool_button_get_active (button));
+}
+
+static void
+vinagre_rdp_tab_set_scaling (VinagreRdpTab *tab,
+                             gboolean       scaling)
+{
+  VinagreRdpTabPrivate *priv = tab->priv;
+  VinagreConnection    *conn = vinagre_tab_get_conn (VINAGRE_TAB (tab));
+  GtkWidget            *scrolled;
+  gint                  window_width, window_height;
+
+  priv->scaling = scaling;
+
+  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->scaling_action),
+                                priv->scaling);
+
+  if (scaling)
+    {
+      scrolled = gtk_widget_get_ancestor (priv->display, GTK_TYPE_SCROLLED_WINDOW);
+      window_width = gtk_widget_get_allocated_width (scrolled);
+      window_height = gtk_widget_get_allocated_height (scrolled);
+
+      gtk_widget_set_size_request (priv->display,
+                                   window_width,
+                                   window_height);
+
+      gtk_widget_set_halign (priv->display, GTK_ALIGN_FILL);
+      gtk_widget_set_valign (priv->display, GTK_ALIGN_FILL);
+    }
+  else
+    {
+      gtk_widget_set_size_request (priv->display,
+                                   vinagre_connection_get_width (VINAGRE_CONNECTION (conn)),
+                                   vinagre_connection_get_height (VINAGRE_CONNECTION (conn)));
+      gtk_widget_set_halign (priv->display, GTK_ALIGN_CENTER);
+      gtk_widget_set_valign (priv->display, GTK_ALIGN_CENTER);
+    }
+
+  gtk_widget_queue_draw_area (priv->display, 0, 0,
+                              gtk_widget_get_allocated_width (priv->display),
+                              gtk_widget_get_allocated_height (priv->display));
+}
+
+static void
+setup_toolbar (VinagreRdpTab *rdp_tab)
+{
+  GtkWidget *toolbar = vinagre_tab_get_toolbar (VINAGRE_TAB (rdp_tab));
+  GtkWidget *button;
+
+  /* Space */
+  button = GTK_WIDGET (gtk_separator_tool_item_new ());
+  gtk_tool_item_set_expand (GTK_TOOL_ITEM (button), TRUE);
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (button), -1);
+
+  /* Scaling */
+  button = GTK_WIDGET (gtk_toggle_tool_button_new ());
+  gtk_tool_button_set_label (GTK_TOOL_BUTTON (button), _("Scaling"));
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (button), _("Scaling"));
+  gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (button), "zoom-fit-best");
+  gtk_widget_show (GTK_WIDGET (button));
+  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (button), -1);
+  g_signal_connect (button, "toggled", G_CALLBACK (scaling_button_clicked), rdp_tab);
+  rdp_tab->priv->scaling_button = button;
+}
 
 static void
 frdp_process_events (freerdp *instance,
                      GQueue  *events)
 {
-  frdpEvent *event;
+  VinagreRdpTab        *rdp_tab = ((frdpContext *) instance->context)->rdp_tab;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  frdpEvent            *event;
+  gint                  x, y;
 
   while (!g_queue_is_empty (events))
     {
@@ -240,10 +383,27 @@ frdp_process_events (freerdp *instance,
                                                 ((frdpEventKey *) event)->code);
                 break;
               case FRDP_EVENT_TYPE_BUTTON:
+                if (priv->scaling)
+                  {
+                    x = (((frdpEventButton *) event)->x - priv->offset_x) / priv->scale;
+                    y = (((frdpEventButton *) event)->y - priv->offset_y) / priv->scale;
+                  }
+                else
+                  {
+                    x = ((frdpEventButton *) event)->x;
+                    y = ((frdpEventButton *) event)->y;
+                  }
+
+                if (x < 0)
+                  x = 0;
+
+                if (y < 0)
+                  y = 0;
+
                 instance->input->MouseEvent (instance->input,
                                              ((frdpEventButton *) event)->flags,
-                                             ((frdpEventButton *) event)->x,
-                                             ((frdpEventButton *) event)->y);
+                                             x,
+                                             y);
                 break;
               default:
                 break;
@@ -261,10 +421,44 @@ frdp_drawing_area_draw (GtkWidget *area,
 {
   VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
   VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  VinagreRdpConnection *conn = VINAGRE_RDP_CONNECTION (vinagre_tab_get_conn (VINAGRE_TAB (rdp_tab)));
+  GtkWidget            *scrolled;
+  double                scale_x, scale_y;
+  gint                  window_width, window_height;
 
   if (priv->surface == NULL)
     return FALSE;
 
+  if (priv->scaling)
+    {
+      scrolled = gtk_widget_get_ancestor (area, GTK_TYPE_SCROLLED_WINDOW);
+      window_width = gtk_widget_get_allocated_width (scrolled);
+      window_height = gtk_widget_get_allocated_height (scrolled);
+
+      scale_x = (double) window_width / vinagre_connection_get_width (VINAGRE_CONNECTION (conn));
+      scale_y = (double) window_height / vinagre_connection_get_height (VINAGRE_CONNECTION (conn));
+
+      priv->scale = scale_x < scale_y ? scale_x : scale_y;
+
+      priv->offset_x = (window_width - vinagre_connection_get_width (VINAGRE_CONNECTION (conn)) * 
priv->scale) / 2.0;
+      priv->offset_y = (window_height - vinagre_connection_get_height (VINAGRE_CONNECTION (conn)) * 
priv->scale) / 2.0;
+
+      if (priv->offset_x < 0)
+        priv->offset_x = 0;
+
+      if (priv->offset_y < 0)
+        priv->offset_y = 0;
+
+      cairo_translate (cr, priv->offset_x, priv->offset_y);
+      cairo_scale (cr, priv->scale, priv->scale);
+
+      if (window_width != gtk_widget_get_allocated_width (area) ||
+          window_height != gtk_widget_get_allocated_height (area))
+        gtk_widget_set_size_request (area,
+                                     window_width,
+                                     window_height);
+    }
+
   cairo_set_source_surface (cr, priv->surface, 0, 0);
   cairo_paint (cr);
 
@@ -286,6 +480,7 @@ frdp_end_paint (rdpContext *context)
   VinagreRdpTab        *rdp_tab = ((frdpContext *) context)->rdp_tab;
   VinagreRdpTabPrivate *priv = rdp_tab->priv;
   rdpGdi               *gdi = context->gdi;
+  double                pos_x, pos_y;
   gint                  x, y, w, h;
 
   if (gdi->primary->hdc->hwnd->invalid->null)
@@ -296,7 +491,21 @@ frdp_end_paint (rdpContext *context)
   w = gdi->primary->hdc->hwnd->invalid->w;
   h = gdi->primary->hdc->hwnd->invalid->h;
 
-  gtk_widget_queue_draw_area (priv->display, x, y, w, h);
+  if (priv->scaling)
+    {
+      pos_x = priv->offset_x + x * priv->scale;
+      pos_y = priv->offset_y + y * priv->scale;
+
+      gtk_widget_queue_draw_area (priv->display,
+                                  floor (pos_x),
+                                  floor (pos_y),
+                                  ceil (pos_x + w * priv->scale) - floor (pos_x),
+                                  ceil (pos_y + h * priv->scale) - floor (pos_y));
+    }
+  else
+    {
+      gtk_widget_queue_draw_area (priv->display, x, y, w, h);
+    }
 }
 
 static BOOL
@@ -845,7 +1054,7 @@ open_freerdp (VinagreRdpTab *rdp_tab)
   rdpSettings          *settings;
   GtkWindow            *window = GTK_WINDOW (vinagre_tab_get_window (tab));
   gboolean              success = TRUE;
-  gboolean              fullscreen;
+  gboolean              fullscreen, scaling;
   gchar                *hostname, *username;
   gint                  port, width, height;
 
@@ -855,6 +1064,7 @@ open_freerdp (VinagreRdpTab *rdp_tab)
                 "width", &width,
                 "height", &height,
                 "fullscreen", &fullscreen,
+                "scaling", &scaling,
                 "username", &username,
                 NULL);
 
@@ -946,8 +1156,6 @@ open_freerdp (VinagreRdpTab *rdp_tab)
   priv->display = gtk_drawing_area_new ();
   if (priv->display)
     {
-      gtk_widget_set_size_request (priv->display, width, height);
-
       g_signal_connect (priv->display, "draw",
                         G_CALLBACK (frdp_drawing_area_draw), rdp_tab);
 
@@ -980,6 +1188,8 @@ open_freerdp (VinagreRdpTab *rdp_tab)
 
       if (fullscreen)
         gtk_window_fullscreen (window);
+
+      vinagre_rdp_tab_set_scaling (rdp_tab, scaling);
     }
 
   priv->key_press_handler_id = g_signal_connect (window, "key-press-event",
@@ -1011,6 +1221,8 @@ static void
 vinagre_rdp_tab_init (VinagreRdpTab *rdp_tab)
 {
   rdp_tab->priv = VINAGRE_RDP_TAB_GET_PRIVATE (rdp_tab);
+
+  rdp_tab->priv->connected_actions = create_connected_actions (rdp_tab);
 }
 
 GtkWidget *


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