[vinagre] Use FreeRDP API in RDP plugin



commit 7ac600bf3014d8d27bc73c69bad2b6f292fba3e6
Author: Marek Kasik <mkasik redhat com>
Date:   Tue Jul 1 13:26:56 2014 +0200

    Use FreeRDP API in RDP plugin
    
    FreeRDP API allows us to implement proper handling of NLA
    authentication by passing a callback during initialization to FreeRDP
    session.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=732496

 configure.ac                  |   10 +-
 data/vinagre.ui               |   35 ++
 plugins/rdp/vinagre-rdp-tab.c |  901 ++++++++++++++++++++++++++++++++++++-----
 3 files changed, 830 insertions(+), 116 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1f105d7..f617044 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,14 +58,16 @@ AS_IF([test "x$have_ssh" = "xyes"],
 AM_CONDITIONAL([VINAGRE_ENABLE_SSH], [test "x$have_ssh" = "xyes"])
 
 # Whether to enable support for RDP.
-RDP_DEPS="$XML2_DEPS"
+RDP_DEPS="freerdp x11"
 AC_ARG_ENABLE([rdp],
   [AS_HELP_STRING([--disable-rdp],
     [Disable Remote Desktop Protocol (RDP) support])])
 
 AS_IF([test "x$enable_rdp" != "xno"],
   [PKG_CHECK_EXISTS([$RDP_DEPS],
-    [have_rdp=yes],
+    [have_rdp=yes
+     PKG_CHECK_EXISTS(freerdp >= 1.1,
+       [AC_DEFINE([HAVE_FREERDP_1_1], [1], [FreeRDP is of version 1.1 or newer])], [])],
     [have_rdp=no])],
   [have_rdp=no])
 
@@ -73,7 +75,7 @@ AS_IF([test "x$have_rdp" = "xyes"],
   [AC_DEFINE([VINAGRE_ENABLE_RDP], [], [Build with RDP support])],
   [RDP_DEPS=""
     AS_IF([test "x$enable_rdp" = "xyes"],
-      [AC_MSG_ERROR([RDP support requested by required dependencies not found])])])
+      [AC_MSG_ERROR([RDP support requested but required dependencies not found])])])
 
 AM_CONDITIONAL([VINAGRE_ENABLE_RDP], [test "x$have_rdp" = "xyes"])
 
@@ -164,7 +166,7 @@ AS_IF([test "x$have_telepathy" = "xyes"],
 AM_CONDITIONAL([VINAGRE_HAVE_TELEPATHY_GLIB], [test "x$have_telepathy" = "xyes"])
 
 # Check required libraries
-PKG_CHECK_MODULES([VINAGRE], [$GLIB_DEPS $GTHREAD_DEPS $GTK_DEPS libsecret-1 $XML2_DEPS $AVAHI_DEPS 
$TELEPATHY_GLIB_DEPS $SSH_DEPS])
+PKG_CHECK_MODULES([VINAGRE], [$GLIB_DEPS $GTHREAD_DEPS $GTK_DEPS libsecret-1 $XML2_DEPS $AVAHI_DEPS 
$TELEPATHY_GLIB_DEPS $SSH_DEPS $RDP_DEPS])
 
 PKG_CHECK_MODULES([VNC], [$GTK_VNC_DEPS $GTK_DEPS $XML2_DEPS])
 
diff --git a/data/vinagre.ui b/data/vinagre.ui
index 3c3c191..041dfe7 100644
--- a/data/vinagre.ui
+++ b/data/vinagre.ui
@@ -206,6 +206,24 @@ Jonh Wendell &lt;jwendell gnome org&gt;</property>
                   </packing>
                 </child>
                 <child>
+                  <object class="GtkLabel" id="domain_label">
+                    <property name="visible">False</property>
+                    <property name="can_focus">False</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | 
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="margin_left">12</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">_Domain:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">domain_entry</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
                   <object class="GtkCheckButton" id="save_credential_check">
                     <property name="label" translatable="yes">_Remember this credential</property>
                     <property name="visible">True</property>
@@ -262,6 +280,23 @@ Jonh Wendell &lt;jwendell gnome org&gt;</property>
                   </packing>
                 </child>
                 <child>
+                  <object class="GtkEntry" id="domain_entry">
+                    <property name="visible">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | 
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="max_length">254</property>
+                    <property name="invisible_char">●</property>
+                    <property name="activates_default">True</property>
+                    <property name="invisible_char_set">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
                   <placeholder/>
                 </child>
               </object>
diff --git a/plugins/rdp/vinagre-rdp-tab.c b/plugins/rdp/vinagre-rdp-tab.c
index abe33e1..1ca9bb6 100644
--- a/plugins/rdp/vinagre-rdp-tab.c
+++ b/plugins/rdp/vinagre-rdp-tab.c
@@ -4,6 +4,7 @@
  * This file is part of vinagre
  *
  * Copyright (C) 2010 - Jonh Wendell <wendell bani com br>
+ * Copyright (C) 2014 - Marek Kasik <mkasik redhat com>
  *
  * 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
@@ -20,13 +21,20 @@
  */
 
 #include <config.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
+#include <errno.h>
 #include <glib/gi18n.h>
-#include <gtk/gtkx.h>
-
-#include <vinagre/vinagre-prefs.h>
+#include <gdk/gdkkeysyms.h>
+#include <freerdp/api.h>
+#include <freerdp/types.h>
+#include <freerdp/freerdp.h>
+#include <freerdp/utils/event.h>
+#include <freerdp/gdi/gdi.h>
+#if HAVE_FREERDP_1_1
+#include <freerdp/locale/keyboard.h>
+#else
+#include <freerdp/kbd/vkcodes.h>
+#include <gdk/gdkx.h>
+#endif
 
 #include "vinagre-rdp-tab.h"
 #include "vinagre-rdp-connection.h"
@@ -34,15 +42,73 @@
 
 #define VINAGRE_RDP_TAB_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), VINAGRE_TYPE_RDP_TAB, 
VinagreRdpTabPrivate))
 
+#define SELECT_TIMEOUT 50
+
+#if !HAVE_FREERDP_1_1
+typedef boolean BOOL;
+typedef uint8   UINT8;
+typedef uint16  UINT16;
+#endif
+
 struct _VinagreRdpTabPrivate
 {
-  GtkWidget *box;
-  GPid pid;
-  guint child;
+  freerdp         *freerdp_session;
+  GtkWidget       *display;
+  cairo_surface_t *surface;
+  GQueue          *events;
+
+  guint            update_id;
+  guint            button_press_handler_id;
+  guint            button_release_handler_id;
+  guint            key_press_handler_id;
+  guint            key_release_handler_id;
+  guint            motion_notify_handler_id;
 };
 
 G_DEFINE_TYPE (VinagreRdpTab, vinagre_rdp_tab, VINAGRE_TYPE_TAB)
 
+static void open_freerdp (VinagreRdpTab *rdp_tab);
+
+struct frdp_context
+{
+  rdpContext     context;
+  VinagreRdpTab *rdp_tab;
+};
+typedef struct frdp_context frdpContext;
+
+typedef enum
+{
+  FRDP_EVENT_TYPE_BUTTON = 0,
+  FRDP_EVENT_TYPE_KEY    = 1
+} frdpEventType;
+
+typedef struct _frdpEventButton frdpEventButton;
+typedef struct _frdpEventKey    frdpEventKey;
+typedef union  _frdpEvent       frdpEvent;
+
+struct _frdpEventKey
+{
+  frdpEventType type;
+  UINT16        code;
+  BOOL          extended;
+  UINT16        flags;
+};
+
+struct _frdpEventButton
+{
+  frdpEventType type;
+  UINT16        x;
+  UINT16        y;
+  UINT16        flags;
+};
+
+union _frdpEvent
+{
+  frdpEventType   type;
+  frdpEventKey    key;
+  frdpEventButton button;
+};
+
 static gchar *
 rdp_tab_get_tooltip (VinagreTab *tab)
 {
@@ -56,170 +122,781 @@ rdp_tab_get_tooltip (VinagreTab *tab)
 }
 
 static void
-rdp_tab_get_dimensions (VinagreTab *tab, int *w, int *h)
+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->freerdp_session)
+    {
+      gdi_free (priv->freerdp_session);
+      freerdp_disconnect (priv->freerdp_session);
+      freerdp_context_free (priv->freerdp_session);
+      g_clear_pointer (&priv->freerdp_session, freerdp_free);
+    }
+
+  if (priv->events)
+    {
+      while (!g_queue_is_empty (priv->events))
+        g_free ((frdpEvent *) g_queue_pop_head (priv->events));
+
+      g_queue_free (priv->events);
+    }
+
+  if (priv->update_id > 0)
+    {
+      g_source_remove (rdp_tab->priv->update_id);
+      rdp_tab->priv->update_id = 0;
+    }
+
+  if (priv->motion_notify_handler_id > 0)
+    {
+      g_signal_handler_disconnect (priv->display, priv->motion_notify_handler_id);
+      priv->motion_notify_handler_id = 0;
+    }
+
+  if (priv->button_press_handler_id > 0)
+    {
+      g_signal_handler_disconnect (priv->display, priv->button_press_handler_id);
+      priv->button_press_handler_id = 0;
+    }
+
+  if (priv->button_release_handler_id > 0)
+    {
+      g_signal_handler_disconnect (priv->display, priv->button_release_handler_id);
+      priv->button_release_handler_id = 0;
+    }
+
+  if (priv->key_press_handler_id > 0)
+    {
+      g_signal_handler_disconnect (window, priv->key_press_handler_id);
+      priv->key_press_handler_id = 0;
+    }
+
+  if (priv->key_release_handler_id > 0)
+    {
+      g_signal_handler_disconnect (window, priv->key_release_handler_id);
+      priv->key_release_handler_id = 0;
+    }
+
+  G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->dispose (object);
+}
+
+static void
+vinagre_rdp_tab_constructed (GObject *object)
 {
-  VinagreRdpTab *rdp_tab = VINAGRE_RDP_TAB (tab);
-  GdkWindow *window = gtk_widget_get_window (rdp_tab->priv->box);
+  VinagreRdpTab *rdp_tab = VINAGRE_RDP_TAB (object);
+
+  if (G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->constructed)
+    G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->constructed (object);
 
-  *w = gdk_window_get_width (window);
-  *h = gdk_window_get_height (window);
+  open_freerdp (rdp_tab);
 }
 
 static void
-emit_connected_signal (GtkSocket *socket, VinagreRdpTab *rdp_tab)
+vinagre_rdp_tab_class_init (VinagreRdpTabClass *klass)
 {
-  g_signal_emit_by_name (rdp_tab, "tab-initialized");
-  gtk_widget_grab_focus (rdp_tab->priv->box);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  VinagreTabClass* tab_class = VINAGRE_TAB_CLASS (klass);
+
+  object_class->constructed = vinagre_rdp_tab_constructed;
+  object_class->dispose = vinagre_rdp_tab_dispose;
+
+  tab_class->impl_get_tooltip = rdp_tab_get_tooltip;
+
+  g_type_class_add_private (object_class, sizeof (VinagreRdpTabPrivate));
 }
 
+static gboolean
+idle_close (VinagreTab *tab)
+{
+  vinagre_notebook_close_tab (vinagre_tab_get_notebook (tab), tab);
+
+  return FALSE;
+}
+
+
 static void
-child_exited (GPid pid, gint status, VinagreRdpTab *rdp_tab)
+frdp_process_events (freerdp *instance,
+                     GQueue  *events)
 {
-  if (rdp_tab->priv->pid > 0)
+  frdpEvent *event;
+
+  while (!g_queue_is_empty (events))
     {
-      g_spawn_close_pid (rdp_tab->priv->pid);
-      rdp_tab->priv->pid = 0;
-      if (WIFEXITED (status))
-        vinagre_tab_remove_from_notebook (VINAGRE_TAB (rdp_tab));
-      else
-        g_signal_emit_by_name (rdp_tab, "tab-disconnected");
+      event = g_queue_pop_head (events);
+      if (event != NULL)
+        {
+          switch (event->type)
+            {
+              case FRDP_EVENT_TYPE_KEY:
+                instance->input->KeyboardEvent (instance->input,
+                                                ((frdpEventKey *) event)->flags,
+                                                ((frdpEventKey *) event)->code);
+                break;
+              case FRDP_EVENT_TYPE_BUTTON:
+                instance->input->MouseEvent (instance->input,
+                                             ((frdpEventButton *) event)->flags,
+                                             ((frdpEventButton *) event)->x,
+                                             ((frdpEventButton *) event)->y);
+                break;
+              default:
+                break;
+            }
+
+          g_free (event);
+        }
     }
 }
 
 static gboolean
-delay_connect (GObject *object)
+frdp_drawing_area_draw (GtkWidget *area,
+                        cairo_t   *cr,
+                        gpointer   user_data)
 {
-  gchar **arg;
-  const gchar *username;
-  gint i;
-  GError *error = NULL;
-  VinagreRdpTab *rdp_tab = VINAGRE_RDP_TAB (object);
-  VinagreTab    *tab = VINAGRE_TAB (object);
-  VinagreConnection *conn = vinagre_tab_get_conn (tab);
+  VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
 
-  username = vinagre_connection_get_username (conn);
-  i = 0;
+  if (priv->surface == NULL)
+    return FALSE;
 
-  arg = g_new (gchar *, 11);
-  arg[i++] = g_strdup ("xfreerdp");
+  cairo_set_source_surface (cr, priv->surface, 0, 0);
+  cairo_paint (cr);
 
-  arg[i++] = g_strdup ("-K");
+  return TRUE;
+}
 
-  if (vinagre_connection_get_fullscreen (conn))
-    arg[i++] = g_strdup ("-f");
+static void
+frdp_begin_paint (rdpContext *context)
+{
+  rdpGdi *gdi = context->gdi;
 
-  arg[i++] = g_strdup ("-g");
-  arg[i++] = g_strdup_printf ("%dx%d",
-                             vinagre_connection_get_width (conn),
-                             vinagre_connection_get_height (conn));
+  gdi->primary->hdc->hwnd->invalid->null = 1;
+  gdi->primary->hdc->hwnd->ninvalid = 0;
+}
+
+static void
+frdp_end_paint (rdpContext *context)
+{
+  VinagreRdpTab        *rdp_tab = ((frdpContext *) context)->rdp_tab;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  rdpGdi               *gdi = context->gdi;
+  gint                  x, y, w, h;
 
-  arg[i++] = g_strdup ("-X");
-  arg[i++] = g_strdup_printf ("%d", (int)gtk_socket_get_id (GTK_SOCKET (rdp_tab->priv->box)));
+  if (gdi->primary->hdc->hwnd->invalid->null)
+    return;
+
+  x = gdi->primary->hdc->hwnd->invalid->x;
+  y = gdi->primary->hdc->hwnd->invalid->y;
+  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);
+}
+
+static BOOL
+frdp_pre_connect (freerdp *instance)
+{
+  rdpSettings *settings = instance->settings;
+
+#if HAVE_FREERDP_1_1
+  settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
+  settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
+  settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
+  settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
+  settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
+  settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
+  settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
+  settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
+  settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
+  settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
+  settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
+  settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
+  settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE;
+  settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE;
+  settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = TRUE;
+  settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
+  settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
+  settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
+  settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
+  settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE;
+  settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
+  settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
+  settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
+  settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
+#else
+  settings->order_support[NEG_DSTBLT_INDEX] = true;
+  settings->order_support[NEG_PATBLT_INDEX] = true;
+  settings->order_support[NEG_SCRBLT_INDEX] = true;
+  settings->order_support[NEG_OPAQUE_RECT_INDEX] = true;
+  settings->order_support[NEG_DRAWNINEGRID_INDEX] = false;
+  settings->order_support[NEG_MULTIDSTBLT_INDEX] = false;
+  settings->order_support[NEG_MULTIPATBLT_INDEX] = false;
+  settings->order_support[NEG_MULTISCRBLT_INDEX] = false;
+  settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = true;
+  settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false;
+  settings->order_support[NEG_LINETO_INDEX] = true;
+  settings->order_support[NEG_POLYLINE_INDEX] = true;
+  settings->order_support[NEG_MEMBLT_INDEX] = true;
+  settings->order_support[NEG_MEM3BLT_INDEX] = false;
+  settings->order_support[NEG_MEMBLT_V2_INDEX] = true;
+  settings->order_support[NEG_MEM3BLT_V2_INDEX] = false;
+  settings->order_support[NEG_SAVEBITMAP_INDEX] = false;
+  settings->order_support[NEG_GLYPH_INDEX_INDEX] = true;
+  settings->order_support[NEG_FAST_INDEX_INDEX] = true;
+  settings->order_support[NEG_FAST_GLYPH_INDEX] = false;
+  settings->order_support[NEG_POLYGON_SC_INDEX] = false;
+  settings->order_support[NEG_POLYGON_CB_INDEX] = false;
+  settings->order_support[NEG_ELLIPSE_SC_INDEX] = false;
+  settings->order_support[NEG_ELLIPSE_CB_INDEX] = false;
+#endif
+
+  return TRUE;
+}
+
+static BOOL
+frdp_post_connect (freerdp *instance)
+{
+  VinagreRdpTab        *rdp_tab = ((frdpContext *) instance->context)->rdp_tab;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  rdpGdi               *gdi;
+  int                   stride;
+
+  gdi_init (instance, CLRBUF_24BPP, NULL);
+  gdi = instance->context->gdi;
+
+  instance->update->BeginPaint = frdp_begin_paint;
+  instance->update->EndPaint = frdp_end_paint;
+
+  stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, gdi->width);
+  rdp_tab->priv->surface = cairo_image_surface_create_for_data ((unsigned char*) gdi->primary_buffer,
+                                                                CAIRO_FORMAT_RGB24,
+                                                                gdi->width,
+                                                                gdi->height,
+                                                                stride);
+  gtk_widget_queue_draw_area (priv->display,
+                              0, 0,
+                              gdi->width, gdi->height);
+
+  vinagre_tab_add_recent_used (VINAGRE_TAB (rdp_tab));
+  vinagre_tab_set_state (VINAGRE_TAB (rdp_tab), VINAGRE_TAB_STATE_CONNECTED);
+
+  return TRUE;
+}
 
-  if (username && *username)
+static gboolean
+update (gpointer user_data)
+{
+  VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  struct timeval        timeout;
+  fd_set                rfds_set;
+  fd_set                wfds_set;
+  void                 *rfds[32];
+  void                 *wfds[32];
+  int                   i;
+  int                   fds;
+  int                   max_fds;
+  int                   rcount = 0;
+  int                   wcount = 0;
+  int                   result;
+
+  memset (rfds, 0, sizeof (rfds));
+  memset (wfds, 0, sizeof (wfds));
+
+  if (!freerdp_get_fds (priv->freerdp_session,
+                        rfds, &rcount,
+                        wfds, &wcount))
     {
-      arg[i++] = g_strdup ("-u");
-      arg[i++] = g_strdup (username);
+      g_warning ("Failed to get FreeRDP file descriptor\n");
+      return FALSE;
     }
 
-  arg[i++] = g_strdup_printf ("%s:%d",
-                             vinagre_connection_get_host (conn),
-                             vinagre_connection_get_port (conn));
-  arg[i++] = NULL;
+  max_fds = 0;
+  FD_ZERO (&rfds_set);
+  FD_ZERO (&wfds_set);
 
-  if (!g_spawn_async (NULL,
-                     arg,
-                     NULL,
-                     G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
-                     NULL,
-                     NULL,
-                     &rdp_tab->priv->pid,
-                     &error))
+  for (i = 0; i < rcount; i++)
     {
-      vinagre_utils_show_error_dialog (_("Error while executing xfreerdp"),
-                               error ? error->message : _("Unknown error"),
-                               GTK_WINDOW (vinagre_tab_get_window (tab)));
-      vinagre_tab_remove_from_notebook (tab);
-      goto _end;
+      fds = (int)(long) (rfds[i]);
+
+      if (fds > max_fds)
+        max_fds = fds;
+
+      FD_SET (fds, &rfds_set);
     }
 
-  rdp_tab->priv->child = g_child_watch_add (rdp_tab->priv->pid,
-                                           (GChildWatchFunc)child_exited, rdp_tab);
-  gtk_widget_show_all (GTK_WIDGET (rdp_tab));
+  if (max_fds == 0)
+    return FALSE;
 
-  vinagre_tab_add_recent_used (tab);
-  vinagre_tab_set_state (tab, VINAGRE_TAB_STATE_CONNECTED);
+  timeout.tv_sec = 0;
+  timeout.tv_usec = SELECT_TIMEOUT;
 
-_end:
-  g_strfreev (arg);
+  result = select (max_fds + 1, &rfds_set, NULL, NULL, &timeout);
+  if (result == -1)
+    {
+      /* these are not errors */
+      if (!((errno == EAGAIN) ||
+            (errno == EWOULDBLOCK) ||
+            (errno == EINPROGRESS) ||
+            (errno == EINTR))) /* signal occurred */
+      {
+        g_warning ("update: select failed\n");
+        return FALSE;
+      }
+    }
 
-  return FALSE;
+  if (!freerdp_check_fds (priv->freerdp_session))
+    {
+      g_warning ("Failed to check FreeRDP file descriptor\n");
+      return FALSE;
+    }
+
+  frdp_process_events (priv->freerdp_session, priv->events);
+
+  if (freerdp_shall_disconnect (priv->freerdp_session))
+    {
+      g_idle_add ((GSourceFunc) idle_close, rdp_tab);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
-static void
-vinagre_rdp_tab_constructed (GObject *object)
+static gboolean
+frdp_key_pressed (GtkWidget   *widget,
+                  GdkEventKey *event,
+                  gpointer     user_data)
 {
-  if (G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->constructed)
-    G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->constructed (object);
+  VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  frdpEventKey         *frdp_event;
+
+  frdp_event = g_new0 (frdpEventKey, 1);
+  frdp_event->type = FRDP_EVENT_TYPE_KEY;
+  frdp_event->flags = event->type == GDK_KEY_PRESS ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE;
 
-  g_idle_add ((GSourceFunc)delay_connect, object);
+#if HAVE_FREERDP_1_1
+  frdp_event->code = freerdp_keyboard_get_rdp_scancode_from_x11_keycode (event->hardware_keycode);
+#else
+  frdp_event->code = freerdp_kbd_get_scancode_by_keycode (event->hardware_keycode, &frdp_event->extended);
+#endif
+
+  g_queue_push_tail (priv->events, frdp_event);
+
+  return TRUE;
 }
 
-static void
-vinagre_rdp_tab_dispose (GObject *object)
+static gboolean
+frdp_button_pressed (GtkWidget      *widget,
+                     GdkEventButton *event,
+                     gpointer        user_data)
 {
-  VinagreRdpTab *rdp_tab = VINAGRE_RDP_TAB (object);
+  VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  frdpEventButton      *frdp_event;
+
+  frdp_event = g_new0 (frdpEventButton, 1);
 
-  if (rdp_tab->priv->pid > 0)
+  frdp_event->type = FRDP_EVENT_TYPE_BUTTON;
+
+  switch (event->button)
     {
-      g_spawn_close_pid (rdp_tab->priv->pid);
-      kill (rdp_tab->priv->pid, SIGTERM);
-      rdp_tab->priv->pid = 0;
+      case 1:
+        frdp_event->flags = PTR_FLAGS_BUTTON1;
+        break;
+
+      case 2:
+        frdp_event->flags = PTR_FLAGS_BUTTON3;
+        break;
+
+      case 3:
+        frdp_event->flags = PTR_FLAGS_BUTTON2;
+        break;
     }
 
-  if (rdp_tab->priv->child > 0)
+  if (frdp_event->flags != 0)
+    {
+      frdp_event->flags |= event->type == GDK_BUTTON_PRESS ? PTR_FLAGS_DOWN : 0;
+
+      frdp_event->x = event->x;
+      frdp_event->y = event->y;
+
+      g_queue_push_tail (priv->events, frdp_event);
+    }
+  else
     {
-      g_source_remove (rdp_tab->priv->child);
-      rdp_tab->priv->child = 0;
+      g_free (frdp_event);
     }
 
-  G_OBJECT_CLASS (vinagre_rdp_tab_parent_class)->dispose (object);
+  return TRUE;
 }
 
-static void 
-vinagre_rdp_tab_class_init (VinagreRdpTabClass *klass)
+static gboolean
+frdp_scroll (GtkWidget      *widget,
+             GdkEventScroll *event,
+             gpointer        user_data)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  VinagreTabClass* tab_class = VINAGRE_TAB_CLASS (klass);
+  VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  frdpEventButton      *frdp_event;
+  gdouble               delta_x = 0.0;
+  gdouble               delta_y = 0.0;
+
+  frdp_event = g_new0 (frdpEventButton, 1);
+  frdp_event->type = FRDP_EVENT_TYPE_BUTTON;
+
+  frdp_event->flags = 0;
+  /* http://msdn.microsoft.com/en-us/library/cc240586.aspx (section 2.2.8.1.1.3.1.1.3) */
+  switch (event->direction)
+    {
+      case GDK_SCROLL_UP:
+        frdp_event->flags = PTR_FLAGS_WHEEL;
+        frdp_event->flags |= 0x0078;
+        break;
+
+      case GDK_SCROLL_DOWN:
+        frdp_event->flags = PTR_FLAGS_WHEEL;
+        frdp_event->flags |= PTR_FLAGS_WHEEL_NEGATIVE;
+        frdp_event->flags |= 0x0088;
+        break;
+
+      case GDK_SCROLL_SMOOTH:
+        if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
+          {
+            if (delta_y != 0.0)
+              {
+                frdp_event->flags = PTR_FLAGS_WHEEL;
+                if (delta_y < 0.0)
+                  {
+                    frdp_event->flags |= 0x0078;
+                  }
+                else
+                  {
+                    frdp_event->flags |= PTR_FLAGS_WHEEL_NEGATIVE;
+                    frdp_event->flags |= 0x0088;
+                  }
+              }
+          }
+        break;
+
+      default:
+        break;
+    }
 
-  object_class->constructed = vinagre_rdp_tab_constructed;
-  object_class->dispose = vinagre_rdp_tab_dispose;
+  if (frdp_event->flags != 0)
+    {
+      frdp_event->x = event->x;
+      frdp_event->y = event->y;
 
-  tab_class->impl_get_tooltip = rdp_tab_get_tooltip;
-  tab_class->impl_get_dimensions = rdp_tab_get_dimensions;
+      g_queue_push_tail (priv->events, frdp_event);
+    }
+  else
+    {
+      g_free (frdp_event);
+    }
 
-  g_type_class_add_private (object_class, sizeof (VinagreRdpTabPrivate));
+  return TRUE;
+}
+
+static gboolean
+frdp_mouse_moved (GtkWidget      *widget,
+                  GdkEventButton *event,
+                  gpointer        user_data)
+{
+  VinagreRdpTab        *rdp_tab = (VinagreRdpTab *) user_data;
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  frdpEventButton      *frdp_event;
+
+  frdp_event = g_new0 (frdpEventButton, 1);
+
+  frdp_event->type = FRDP_EVENT_TYPE_BUTTON;
+  frdp_event->flags = PTR_FLAGS_MOVE;
+  frdp_event->x = event->x;
+  frdp_event->y = event->y;
+
+  g_queue_push_tail (priv->events, frdp_event);
+
+  return TRUE;
 }
 
 static void
-vinagre_rdp_tab_init (VinagreRdpTab *rdp_tab)
+entry_text_changed_cb (GtkEntry   *entry,
+                       GtkBuilder *builder)
 {
-  rdp_tab->priv = VINAGRE_RDP_TAB_GET_PRIVATE (rdp_tab);
+  const gchar *text;
+  GtkWidget   *widget;
+  gsize        username_length;
+  gsize        password_length;
 
-  rdp_tab->priv->pid = 0;
-  rdp_tab->priv->child = 0;
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "username_entry"));
+  text = gtk_entry_get_text (GTK_ENTRY (widget));
+  username_length = strlen (text);
 
-  /* Create the rdp widget */
-  rdp_tab->priv->box = gtk_socket_new ();
-  gtk_widget_set_can_focus (rdp_tab->priv->box, TRUE);
-  vinagre_tab_add_view (VINAGRE_TAB (rdp_tab), rdp_tab->priv->box);
-  gtk_widget_show (rdp_tab->priv->box);
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry"));
+  text = gtk_entry_get_text (GTK_ENTRY (widget));
+  password_length = strlen (text);
 
-  g_signal_connect (rdp_tab->priv->box,
-                   "plug-added",
-                   G_CALLBACK (emit_connected_signal),
-                   rdp_tab);
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
+  gtk_widget_set_sensitive (widget, password_length > 0 && username_length > 0);
+}
+
+static gboolean
+frdp_authenticate (freerdp  *instance,
+                   char    **username,
+                   char    **password,
+                   char    **domain)
+{
+  VinagreTab        *tab = VINAGRE_TAB (((frdpContext *) instance->context)->rdp_tab);
+  VinagreConnection *conn = vinagre_tab_get_conn (tab);
+  const gchar       *user_name;
+  const gchar       *domain_name;
+  GtkBuilder        *builder;
+  GtkWidget         *dialog;
+  GtkWidget         *widget;
+  GtkWidget         *username_entry;
+  GtkWidget         *password_entry;
+  GtkWidget         *domain_entry;
+  gboolean           save_credential_check_visible;
+  gboolean           domain_label_visible;
+  gboolean           domain_entry_visible;
+  gint               response;
+
+  builder = vinagre_utils_get_builder ();
+
+  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "auth_required_dialog"));
+  gtk_window_set_modal ((GtkWindow *) dialog, TRUE);
+  gtk_window_set_transient_for ((GtkWindow *) dialog, GTK_WINDOW (vinagre_tab_get_window (tab)));
+
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "host_label"));
+  gtk_label_set_text (GTK_LABEL (widget), vinagre_connection_get_host (conn));
+
+  username_entry = GTK_WIDGET (gtk_builder_get_object (builder, "username_entry"));
+  password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry"));
+  domain_entry = GTK_WIDGET (gtk_builder_get_object (builder, "domain_entry"));
+
+  if (*username != NULL && *username[0] != '\0')
+    {
+      gtk_entry_set_text (GTK_ENTRY (username_entry), *username);
+      gtk_widget_grab_focus (password_entry);
+    }
 
+  g_signal_connect (username_entry, "changed", G_CALLBACK (entry_text_changed_cb), builder);
+  g_signal_connect (password_entry, "changed", G_CALLBACK (entry_text_changed_cb), builder);
+
+
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "save_credential_check"));
+  save_credential_check_visible = gtk_widget_get_visible (widget);
+  gtk_widget_set_visible (widget, FALSE);
+
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "domain_label"));
+  domain_label_visible = gtk_widget_get_visible (widget);
+  gtk_widget_set_visible (widget, TRUE);
+
+  domain_entry_visible = gtk_widget_get_visible (domain_entry);
+  gtk_widget_set_visible (domain_entry, TRUE);
+
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_hide (dialog);
+
+
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "save_credential_check"));
+  gtk_widget_set_visible (widget, save_credential_check_visible);
+
+  widget = GTK_WIDGET (gtk_builder_get_object (builder, "domain_label"));
+  gtk_widget_set_visible (widget, domain_label_visible);
+
+  gtk_widget_set_visible (domain_entry, domain_entry_visible);
+
+
+  if (response == GTK_RESPONSE_OK)
+    {
+      domain_name = gtk_entry_get_text (GTK_ENTRY (domain_entry));
+      if (g_strcmp0 (*domain, domain_name) != 0)
+        *domain = g_strdup (domain_name);
+
+      user_name = gtk_entry_get_text (GTK_ENTRY (username_entry));
+      if (g_strcmp0 (*username, user_name) != 0)
+        *username = g_strdup (user_name);
+
+      *password = g_strdup (gtk_entry_get_text (GTK_ENTRY (password_entry)));
+
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+static void
+open_freerdp (VinagreRdpTab *rdp_tab)
+{
+  VinagreRdpTabPrivate *priv = rdp_tab->priv;
+  VinagreTab           *tab = VINAGRE_TAB (rdp_tab);
+  VinagreConnection    *conn = vinagre_tab_get_conn (tab);
+  rdpSettings          *settings;
+  GtkWindow            *window = GTK_WINDOW (vinagre_tab_get_window (tab));
+  gboolean              success = TRUE;
+  gboolean              fullscreen;
+  gchar                *hostname, *username;
+  gint                  port, width, height;
+
+  g_object_get (conn,
+                "port", &port,
+                "host", &hostname,
+                "width", &width,
+                "height", &height,
+                "fullscreen", &fullscreen,
+                "username", &username,
+                NULL);
+
+  priv->events = g_queue_new ();
+
+  /* Setup FreeRDP session */
+  priv->freerdp_session = freerdp_new ();
+  priv->freerdp_session->PreConnect = frdp_pre_connect;
+  priv->freerdp_session->PostConnect = frdp_post_connect;
+  priv->freerdp_session->Authenticate = frdp_authenticate;
+
+#if HAVE_FREERDP_1_1
+  priv->freerdp_session->ContextSize = sizeof (frdpContext);
+#else
+  priv->freerdp_session->context_size = sizeof (frdpContext);
+#endif
+
+  freerdp_context_new (priv->freerdp_session);
+  ((frdpContext *) priv->freerdp_session->context)->rdp_tab = rdp_tab;
+
+  /* Set FreeRDP settings */
+  settings = priv->freerdp_session->settings;
+
+  /* Security settings */
+#if HAVE_FREERDP_1_1
+  settings->RdpSecurity = TRUE;
+  settings->TlsSecurity = TRUE;
+  settings->NlaSecurity = TRUE;
+  settings->DisableEncryption = FALSE;
+  settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
+  settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
+#else
+  settings->rdp_security = true;
+  settings->tls_security = true;
+  settings->nla_security = true;
+  settings->encryption = true;
+  settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
+  settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
+#endif
+
+  /* Set display size */
+#if HAVE_FREERDP_1_1
+  settings->DesktopWidth = width;
+  settings->DesktopHeight = height;
+#else
+  settings->width = width;
+  settings->height = height;
+#endif
+
+  /* Set hostname */
+#if HAVE_FREERDP_1_1
+  settings->WindowTitle = g_strdup (hostname);
+  settings->ServerHostname = g_strdup (hostname);
+  settings->ServerPort = port;
+#else
+  settings->window_title = g_strdup (hostname);
+  settings->hostname = g_strdup (hostname);
+  settings->port = port;
+#endif
+
+  /* Set username */
+  username = g_strstrip (username);
+  if (username != NULL && username[0] != '\0')
+    {
+#if HAVE_FREERDP_1_1
+      settings->Username = g_strdup (username);
+#else
+      settings->username = g_strdup (username);
+#endif
+    }
+
+  /* Set keyboard layout */
+#if HAVE_FREERDP_1_1
+  freerdp_keyboard_init (KBD_US);
+#else
+  freerdp_kbd_init (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), KBD_US);
+#endif
+
+  /* Setup display for FreeRDP session */
+  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);
+
+      gtk_widget_add_events (priv->display,
+                             GDK_POINTER_MOTION_MASK |
+                             GDK_BUTTON_PRESS_MASK |
+                             GDK_BUTTON_RELEASE_MASK |
+                             GDK_SCROLL_MASK |
+                             GDK_SMOOTH_SCROLL_MASK);
+
+      priv->button_press_handler_id = g_signal_connect (priv->display, "button-press-event",
+                                                        G_CALLBACK (frdp_button_pressed),
+                                                        rdp_tab);
+
+      priv->button_release_handler_id = g_signal_connect (priv->display, "button-release-event",
+                                                          G_CALLBACK (frdp_button_pressed),
+                                                          rdp_tab);
+
+      priv->button_release_handler_id = g_signal_connect (priv->display, "scroll-event",
+                                                          G_CALLBACK (frdp_scroll),
+                                                          rdp_tab);
+
+      priv->motion_notify_handler_id = g_signal_connect (priv->display, "motion-notify-event",
+                                                         G_CALLBACK (frdp_mouse_moved),
+                                                         rdp_tab);
+
+      gtk_widget_show (priv->display);
+
+      vinagre_tab_add_view (VINAGRE_TAB (rdp_tab), priv->display);
+
+      if (fullscreen)
+        gtk_window_fullscreen (window);
+    }
+
+  priv->key_press_handler_id = g_signal_connect (window, "key-press-event",
+                                                 G_CALLBACK (frdp_key_pressed),
+                                                 rdp_tab);
+
+  priv->key_release_handler_id = g_signal_connect (window, "key-release-event",
+                                                   G_CALLBACK (frdp_key_pressed),
+                                                   rdp_tab);
+
+  /* Run FreeRDP session */
+  success = freerdp_connect (priv->freerdp_session);
+
+  if (!success)
+    {
+      gtk_window_unfullscreen (window);
+      vinagre_utils_show_error_dialog (_("Error connecting to host."),
+                                       NULL,
+                                       window);
+      g_idle_add ((GSourceFunc) idle_close, rdp_tab);
+    }
+  else
+    {
+      priv->update_id = g_idle_add ((GSourceFunc) update, rdp_tab);
+    }
+}
+
+static void
+vinagre_rdp_tab_init (VinagreRdpTab *rdp_tab)
+{
+  rdp_tab->priv = VINAGRE_RDP_TAB_GET_PRIVATE (rdp_tab);
 }
 
 GtkWidget *


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