[gtk-frdp] Fixed #7: Added RDP mouse cursor support



commit 3a5f1356864339a5a9af27ce6e9464b8f0c5c5f5
Author: akallabeth <armin novak thincast com>
Date:   Mon Jul 8 11:07:16 2019 +0000

    Fixed #7: Added RDP mouse cursor support

 src/frdp-display.c |  26 ++++++-
 src/frdp-session.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/frdp-session.h |   3 +
 3 files changed, 244 insertions(+), 1 deletion(-)
---
diff --git a/src/frdp-display.c b/src/frdp-display.c
index c7307d2..a04b879 100644
--- a/src/frdp-display.c
+++ b/src/frdp-display.c
@@ -199,6 +199,26 @@ frdp_display_scroll_event (GtkWidget      *widget,
   return TRUE;
 }
 
+static gboolean
+frdp_enter_notify_event (GtkWidget            *widget,
+                         GdkEventCrossing  *event)
+{
+  FrdpDisplay *self = FRDP_DISPLAY (widget);
+  FrdpDisplayPrivate *priv = frdp_display_get_instance_private (self);
+  frdp_session_mouse_pointer(priv->session, TRUE);
+  return TRUE;
+}
+
+static gboolean
+frdp_leave_notify_event (GtkWidget            *widget,
+                         GdkEventCrossing  *event)
+{
+  FrdpDisplay *self = FRDP_DISPLAY (widget);
+  FrdpDisplayPrivate *priv = frdp_display_get_instance_private (self);
+  frdp_session_mouse_pointer(priv->session, FALSE);
+  return TRUE;
+}
+
 static void
 frdp_display_disconnected (GObject  *source_object,
                            gpointer  user_data)
@@ -310,6 +330,8 @@ frdp_display_class_init (FrdpDisplayClass *klass)
   widget_class->button_press_event = frdp_display_button_press_event;
   widget_class->button_release_event = frdp_display_button_press_event;
   widget_class->scroll_event = frdp_display_scroll_event;
+  widget_class->enter_notify_event = frdp_enter_notify_event;
+  widget_class->leave_notify_event = frdp_leave_notify_event;
 
   g_object_class_install_property (gobject_class,
                                    PROP_USERNAME,
@@ -365,7 +387,9 @@ frdp_display_init (FrdpDisplay *self)
                          GDK_BUTTON_RELEASE_MASK |
                          GDK_SCROLL_MASK |
                          GDK_SMOOTH_SCROLL_MASK |
-                         GDK_KEY_PRESS_MASK);
+                         GDK_KEY_PRESS_MASK |
+                         GDK_ENTER_NOTIFY_MASK |
+                         GDK_LEAVE_NOTIFY_MASK);
 
   gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
 
diff --git a/src/frdp-session.c b/src/frdp-session.c
index 5ce5f86..45643be 100644
--- a/src/frdp-session.c
+++ b/src/frdp-session.c
@@ -28,6 +28,13 @@
 
 #define SELECT_TIMEOUT 50
 
+struct frdp_pointer
+{
+       rdpPointer pointer;
+       cairo_surface_t *data;
+};
+typedef struct frdp_pointer frdpPointer;
+
 struct _FrdpSessionPrivate
 {
   freerdp      *freerdp_session;
@@ -47,6 +54,10 @@ struct _FrdpSessionPrivate
   gchar *username;
   gchar *password;
   guint  port;
+
+  gboolean show_cursor;
+  gboolean cursor_null;
+  frdpPointer *cursor;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (FrdpSession, frdp_session, G_TYPE_OBJECT)
@@ -78,6 +89,197 @@ struct frdp_context
 };
 typedef struct frdp_context frdpContext;
 
+static void
+frdp_session_update_mouse_pointer (FrdpSession  *self)
+{
+  FrdpSessionPrivate *priv = self->priv;
+  GdkCursor *cursor;
+  GdkDisplay *display;
+  GdkWindow  *window;
+
+  window = gtk_widget_get_parent_window(priv->display);
+  display = gtk_widget_get_display(priv->display);
+  if (priv->show_cursor && priv->cursor_null) {
+    cairo_surface_t *surface;
+    cairo_t *cairo;
+
+    /* Create a 1x1 image with transparent color */
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+    cairo = cairo_create (surface);
+    cairo_set_source_rgba (cairo, 0.0, 0.0, 0.0, 0.0);
+    cairo_set_line_width(cairo, 1);
+    cairo_rectangle(cairo, 0, 0, 1, 1);
+    cairo_fill (cairo);
+
+    cursor =  gdk_cursor_new_from_surface (display, surface, 0, 0);
+    cairo_surface_destroy (surface);
+    cairo_destroy (cairo);
+    cairo_surface_destroy (surface);
+  } else if (!priv->show_cursor || !priv->cursor)
+      /* No cursor set or none to show */
+    cursor = gdk_cursor_new_from_name (display, "default");
+  else {
+    rdpPointer *pointer = &priv->cursor->pointer;
+    double scale = self->priv->scale;
+    double x = priv->cursor->pointer.xPos * scale;
+    double y = priv->cursor->pointer.yPos * scale;
+    double w = pointer->width * scale;
+    double h = pointer->height * scale;
+    cairo_surface_t *surface;
+    cairo_t *cairo;
+
+    if (!self->priv->scaling) {
+      scale = 1.0;
+    }
+
+    /* Scale the source image according to current settings. */
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+    cairo = cairo_create (surface);
+
+    cairo_scale(cairo, scale, scale);
+    cairo_set_source_surface (cairo, priv->cursor->data, 0, 0);
+    cairo_paint (cairo);
+
+    cairo_fill (cairo);
+    cursor =  gdk_cursor_new_from_surface (display, surface, x, y);
+    cairo_surface_destroy (surface);
+    cairo_destroy (cairo);
+  }
+
+  gdk_window_set_cursor (window, cursor);
+}
+
+static BOOL
+frdp_Pointer_New(rdpContext* context, rdpPointer* pointer)
+{
+  frdpContext *fcontext = (frdpContext*) context;
+  frdpPointer *fpointer = (frdpPointer*) pointer;
+  int stride;
+       unsigned char *data;
+  cairo_surface_t *surface;
+
+       if (!fcontext || !fpointer)
+               return FALSE;
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, pointer->width,
+                                        pointer->height);
+  if (!surface) {
+    return FALSE;
+  }
+
+  { /* FreeRDP BUG https://github.com/FreeRDP/FreeRDP/issues/5061
+     * the function freerdp_image_copy_from_pointer_data
+     * does not initialize the buffer which results in broken alpha data. */
+    cairo_t* cairo = cairo_create (surface);
+
+    cairo_set_source_rgba (cairo, 0.0, 0.0, 0.0, 1.0);
+    cairo_fill (cairo);
+    cairo_paint (cairo);
+    cairo_destroy (cairo);
+  }
+
+  data = cairo_image_surface_get_data (surface);
+  if (!data) {
+    goto fail;
+  }
+
+  stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, pointer->width);
+       if (!freerdp_image_copy_from_pointer_data (data, PIXEL_FORMAT_BGRA32,
+                                             stride, 0, 0, pointer->width,
+                                             pointer->height,
+                                             pointer->xorMaskData,
+                                             pointer->lengthXorMask,
+                                             pointer->andMaskData,
+                                             pointer->lengthAndMask,
+                                             pointer->xorBpp,
+                                             &context->gdi->palette))
+    goto fail;
+
+  fpointer->data = surface;
+  return TRUE;
+fail:
+  if (surface)
+    cairo_surface_destroy (surface);
+       return FALSE;
+}
+
+static void
+frdp_Pointer_Free (rdpContext* context, rdpPointer* pointer)
+{
+  frdpContext *fcontext = (frdpContext*) context;
+  frdpPointer *fpointer = (frdpPointer*) pointer;
+
+  if (fpointer && fpointer->data) {
+    cairo_surface_destroy (fpointer->data);
+    fpointer->data = NULL;
+  }
+}
+
+static BOOL
+frdp_Pointer_Set (rdpContext* context,
+                  const rdpPointer* pointer)
+{
+  frdpContext *fcontext = (frdpContext*) context;
+  frdpPointer *fpointer = (frdpPointer*) pointer;
+  FrdpSessionPrivate *priv = fcontext->self->priv;
+
+  priv->cursor = fpointer;
+  priv->cursor_null = FALSE;
+
+  frdp_session_update_mouse_pointer (fcontext->self);
+       return TRUE;
+}
+
+static BOOL
+frdp_Pointer_SetNull (rdpContext* context)
+{
+  frdpContext *fcontext = (frdpContext*) context;
+  FrdpSessionPrivate *priv = fcontext->self->priv;
+  unsigned char *data;
+  cairo_surface_t *surface;
+
+  priv->cursor = NULL;
+  priv->cursor_null = TRUE;
+
+  frdp_session_update_mouse_pointer (fcontext->self);
+       return TRUE;
+}
+
+static BOOL
+frdp_Pointer_SetDefault (rdpContext* context)
+{
+  frdpContext *fcontext = (frdpContext*) context;
+   FrdpSessionPrivate *priv = fcontext->self->priv;
+
+  priv->cursor = NULL;
+  priv->cursor_null = FALSE;
+  frdp_session_update_mouse_pointer (fcontext->self);
+       return TRUE;
+}
+
+static BOOL
+frdp_Pointer_SetPosition (rdpContext* context, UINT32 x, UINT32 y)
+{
+  frdpContext *fcontext = (frdpContext*) context;
+  /* TODO */
+       return TRUE;
+}
+
+static void
+frdp_register_pointer (rdpGraphics* graphics)
+{
+       rdpPointer pointer;
+
+       pointer.size = sizeof(frdpPointer);
+       pointer.New = frdp_Pointer_New;
+       pointer.Free = frdp_Pointer_Free;
+       pointer.Set = frdp_Pointer_Set;
+       pointer.SetNull = frdp_Pointer_SetNull;
+       pointer.SetDefault = frdp_Pointer_SetDefault;
+       pointer.SetPosition = frdp_Pointer_SetPosition;
+       graphics_register_pointer(graphics, &pointer);
+}
+
 static guint32
 frdp_session_get_best_color_depth (FrdpSession *self)
 {
@@ -113,6 +315,8 @@ frdp_session_configure_event (GtkWidget *widget,
     self->priv->offset_x = (width - settings->DesktopWidth * self->priv->scale) / 2.0;
     self->priv->offset_y = (height - settings->DesktopHeight * self->priv->scale) / 2.0;
   }
+
+  frdp_session_update_mouse_pointer (self);
 }
 
 static void
@@ -277,6 +481,8 @@ frdp_post_connect (freerdp *freerdp_session)
   gdi_init (freerdp_session, color_format);
   gdi = freerdp_session->context->gdi;
 
+  frdp_register_pointer (freerdp_session->context->graphics);
+  pointer_cache_register_callbacks(freerdp_session->context->update);
   freerdp_session->update->BeginPaint = frdp_begin_paint;
   freerdp_session->update->EndPaint = frdp_end_paint;
 
@@ -701,6 +907,16 @@ frdp_session_mouse_event (FrdpSession          *self,
   }
 }
 
+void
+frdp_session_mouse_pointer  (FrdpSession          *self,
+                             gboolean              enter)
+{
+  FrdpSessionPrivate *priv = self->priv;
+
+  priv->show_cursor = enter;
+  frdp_session_update_mouse_pointer (self);
+}
+
 static unsigned char keycode_scancodes[] = {
    0,  0,  0,  0,  0,  0,  0, 28,
   29, 53, 55, 56,  0, 71, 72, 73,
diff --git a/src/frdp-session.h b/src/frdp-session.h
index a9a146d..b88b217 100644
--- a/src/frdp-session.h
+++ b/src/frdp-session.h
@@ -80,6 +80,9 @@ void         frdp_session_mouse_event    (FrdpSession          *self,
                                           guint16               x,
                                           guint16               y);
 
+void         frdp_session_mouse_pointer  (FrdpSession          *self,
+                                          gboolean              enter);
+
 void         frdp_session_send_key       (FrdpSession          *self,
                                           FrdpKeyEvent          event,
                                           guint16               keycode);


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