--- gnome-connections-41.2/src/display-view.vala +++ gnome-connections-41.2/src/display-view.vala @@ -104,23 +104,8 @@ namespace Connections { if (event.type == EventType.GRAB_BROKEN) return false; - if (event_box.get_child () != null) { - var child = event_box.get_child (); - var offset_x = (get_allocated_width () - child.get_allocated_width ()) / 2.0; - var offset_y = (get_allocated_height () - child.get_allocated_height ()) / 2.0; - - switch (event.get_event_type ()) { - case Gdk.EventType.MOTION_NOTIFY: - event.motion.x -= offset_x; - event.motion.y -= offset_y; - break; - - default: - break; - } - - child.event (event); - } + if (event_box.get_child () != null) + event_box.get_child ().event (event); return false; } --- gnome-connections-41.2/src/rdp-connection.vala +++ gnome-connections-41.2/src/rdp-connection.vala @@ -66,10 +66,10 @@ namespace Connections { display.bind_property ("username", this, "username", BindingFlags.BIDIRECTIONAL); display.bind_property ("password", this, "password", BindingFlags.BIDIRECTIONAL); - display.rdp_connected.connect (() => { show (); }); + display.rdp_connected.connect (on_rdp_connection_connected_cb); //display.rdp_needs_authentication.connect (on_rdp_auth_credential_cb); display.rdp_auth_failure.connect (auth_failed); - //display.size_allocate.connect (scale); + display.size_allocate.connect (scale); need_username = need_password = true; } @@ -101,6 +101,10 @@ namespace Connections { return; } + else { + display.username = username; + display.password = password; + } display.open_host (host, port); connected = true; @@ -123,6 +127,23 @@ namespace Connections { handle_auth (); } + + private void on_rdp_connection_connected_cb () { + connected = true; + scaling = true; + + display.grab_focus (); + scale (); + show (); + } + + public void scale () { + if (!display.is_open ()) + return; + + display.scaling = display.hexpand = true; + display.width_request = display.height_request = 0; + } } private class FrdpDisplay : Frdp.Display { --- gnome-connections-41.2/subprojects/gtk-frdp/src/frdp-session.c +++ gnome-connections-41.2/subprojects/gtk-frdp/src/frdp-session.c @@ -19,6 +19,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -26,7 +30,7 @@ #include "frdp-session.h" -#define SELECT_TIMEOUT 50 +#define SELECT_TIMEOUT 10 #define FRDP_CONNECTION_THREAD_MAX_ERRORS 10 struct frdp_pointer @@ -41,6 +45,7 @@ struct _FrdpSessionPrivate freerdp *freerdp_session; GtkWidget *display; + cairo_format_t cairo_format; cairo_surface_t *surface; gboolean scaling; double scale; @@ -59,6 +64,8 @@ struct _FrdpSessionPrivate gboolean show_cursor; gboolean cursor_null; frdpPointer *cursor; + GQueue *area_draw_queue; /* elem: GdkRectangle */ + GMutex area_draw_mutex; }; G_DEFINE_TYPE_WITH_PRIVATE (FrdpSession, frdp_session, G_TYPE_OBJECT) @@ -91,6 +98,16 @@ struct frdp_context }; typedef struct frdp_context frdpContext; +static void queue_draw_area (FrdpSession *self, + gint x, + gint y, + gint width, + gint height); + +static void frdp_session_configure_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data); + static void frdp_session_update_mouse_pointer (FrdpSession *self) { @@ -153,143 +170,58 @@ frdp_session_update_mouse_pointer (FrdpS gdk_window_set_cursor (window, cursor); } -static BOOL -frdp_Pointer_New(rdpContext* context, rdpPointer* pointer) +static guint32 +frdp_session_get_best_color_depth (FrdpSession *self) { - 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); - } + GdkScreen *display; + GdkVisual *visual; - 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; + display = gdk_screen_get_default (); + visual = gdk_screen_get_rgba_visual (display); - fpointer->data = surface; - return TRUE; -fail: - if (surface) - cairo_surface_destroy (surface); - return FALSE; + return gdk_visual_get_depth (visual); } static void -frdp_Pointer_Free (rdpContext* context, rdpPointer* pointer) +create_cairo_surface (FrdpSession *self) { - frdpPointer *fpointer = (frdpPointer*) pointer; + FrdpSessionPrivate *priv = self->priv; + rdpGdi *gdi; + gint stride; - if (fpointer && fpointer->data) { - cairo_surface_destroy (fpointer->data); - fpointer->data = NULL; + if (priv->surface != NULL) { + cairo_surface_mark_dirty (priv->surface); + cairo_surface_destroy (priv->surface); + self->priv->surface = 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; - priv->cursor = NULL; - priv->cursor_null = TRUE; + gdi = priv->freerdp_session->context->gdi; - 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) -{ - return TRUE; -} - -static void -frdp_register_pointer (rdpGraphics* graphics) -{ - rdpPointer pointer; + stride = cairo_format_stride_for_width (priv->cairo_format, gdi->width); + self->priv->surface = + cairo_image_surface_create_for_data ((unsigned char*) gdi->primary_buffer, + priv->cairo_format, + gdi->width, + gdi->height, + stride); + cairo_surface_flush (priv->surface); - 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); + frdp_session_configure_event (priv->display, NULL, self); } -static guint32 -frdp_session_get_best_color_depth (FrdpSession *self) +static gboolean +frdp_desktop_resize (rdpContext *context) { - GdkScreen *display; - GdkVisual *visual; - - display = gdk_screen_get_default (); - visual = gdk_screen_get_rgba_visual (display); + FrdpSession *self = ((frdpContext *) context)->self; + rdpGdi *gdi = context->gdi; - return gdk_visual_get_depth (visual); + if (gdi_resize (gdi, + context->settings->DesktopWidth, + context->settings->DesktopHeight)) { + return TRUE; + } else { + return FALSE; + } } static void @@ -298,22 +230,37 @@ frdp_session_configure_event (GtkWidget gpointer user_data) { FrdpSession *self = (FrdpSession*) user_data; + FrdpSessionPrivate *priv = self->priv; + GtkWidget *scrolled; rdpSettings *settings = self->priv->freerdp_session->settings; - double width, height; + double width, height, widget_ratio, server_ratio; + rdpGdi *gdi; - if (self->priv->scaling) { - width = (double)gtk_widget_get_allocated_width (widget); - height = (double)gtk_widget_get_allocated_height (widget); + if (priv->freerdp_session == NULL) + return; + + gdi = priv->freerdp_session->context->gdi; + + if (priv->surface == NULL) + create_cairo_surface (self); - if (width < height) - self->priv->scale = width / settings->DesktopWidth; - else - self->priv->scale = height / settings->DesktopHeight; + scrolled = gtk_widget_get_ancestor (widget, GTK_TYPE_SCROLLED_WINDOW); + width = (double)gtk_widget_get_allocated_width (scrolled); + height = (double)gtk_widget_get_allocated_height (scrolled); - settings->DesktopScaleFactor = self->priv->scale; + if (priv->scaling) { + widget_ratio = height > 0 ? width / height : 1.0; + server_ratio = settings->DesktopHeight > 0 ? (double) settings->DesktopWidth / settings->DesktopHeight : 1.0; + + if (widget_ratio > server_ratio) + self->priv->scale = height / settings->DesktopHeight; + else + self->priv->scale = width / settings->DesktopWidth; - self->priv->offset_x = (width - settings->DesktopWidth * self->priv->scale) / 2.0; - self->priv->offset_y = (height - settings->DesktopHeight * self->priv->scale) / 2.0; + self->priv->offset_x = (width - settings->DesktopWidth * self->priv->scale) / 2.0; + self->priv->offset_y = (height - settings->DesktopHeight * self->priv->scale) / 2.0; + } else { + gtk_widget_set_size_request (priv->display, gdi->width, gdi->height); } frdp_session_update_mouse_pointer (self); @@ -335,6 +282,23 @@ frdp_session_draw (GtkWidget *widget, { FrdpSession *self = (FrdpSession*) user_data; + if (!self->priv->is_connected) + return FALSE; + + if (self->priv->surface == NULL || + (self->priv->freerdp_session->context->gdi->width != cairo_image_surface_get_width (self->priv->surface) || + self->priv->freerdp_session->context->gdi->height != cairo_image_surface_get_height (self->priv->surface))) { + create_cairo_surface (self); + } + + cairo_rectangle (cr, + self->priv->offset_x, + self->priv->offset_y, + cairo_image_surface_get_width (self->priv->surface) * self->priv->scale, + cairo_image_surface_get_height (self->priv->surface) * self->priv->scale); + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_fill (cr); + if (self->priv->scaling) { cairo_translate (cr, self->priv->offset_x, self->priv->offset_y); cairo_scale (cr, self->priv->scale, self->priv->scale); @@ -385,9 +350,61 @@ frdp_authenticate (freerdp *freerdp_ses domain); } +static void +frdp_on_channel_connected_event_handler (void *context, + ChannelConnectedEventArgs *e) +{ + frdpContext *ctx = (frdpContext *) context; + + if (strcmp (e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { + gdi_graphics_pipeline_init (ctx->context.gdi, (RdpgfxClientContext *) e->pInterface); + } else if (strcmp (e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0) { + gdi_video_geometry_init (ctx->context.gdi, (GeometryClientContext *) e->pInterface); + } else if (strcmp (e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0) { + gdi_video_control_init (ctx->context.gdi, (VideoClientContext *) e->pInterface); + } else if (strcmp (e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0) { + gdi_video_data_init (ctx->context.gdi, (VideoClientContext *) e->pInterface); + } +} + +static void +frdp_on_channel_disconnected_event_handler (void *context, + ChannelDisconnectedEventArgs *e) +{ + frdpContext *ctx = (frdpContext *) context; + + if (strcmp (e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { + gdi_graphics_pipeline_uninit (ctx->context.gdi, (RdpgfxClientContext *) e->pInterface); + } else if (strcmp (e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0) { + gdi_video_geometry_uninit (ctx->context.gdi, (GeometryClientContext *) e->pInterface); + } else if (strcmp (e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0) { + gdi_video_control_uninit (ctx->context.gdi, (VideoClientContext *) e->pInterface); + } else if (strcmp (e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0) { + gdi_video_data_uninit (ctx->context.gdi, (VideoClientContext *) e->pInterface); + } +} + +static gboolean +frdp_load_channels (freerdp *instance) +{ + instance->context->settings->DeviceRedirection = FALSE; + if (!freerdp_client_load_addins (instance->context->channels, instance->context->settings)) + return FALSE; + + return TRUE; +} + static gboolean frdp_pre_connect (freerdp *freerdp_session) { + rdpContext *context = freerdp_session->context; + + PubSub_SubscribeChannelConnected (context->pubSub, + frdp_on_channel_connected_event_handler); + PubSub_SubscribeChannelDisconnected (context->pubSub, + frdp_on_channel_disconnected_event_handler); + + frdp_load_channels (freerdp_session); return TRUE; } @@ -402,6 +419,30 @@ frdp_begin_paint (rdpContext *context) return TRUE; } +static void +queue_draw_area (FrdpSession *self, + gint x, + gint y, + gint width, + gint height) +{ + FrdpSessionPrivate *priv = self->priv; + GdkRectangle *rectangle; + + rectangle = g_new (GdkRectangle, 1); + rectangle->x = x; + rectangle->y = y; + rectangle->width = width; + rectangle->height = height; + + g_mutex_lock (&priv->area_draw_mutex); + + if (priv->area_draw_queue != NULL) + g_queue_push_tail (priv->area_draw_queue, rectangle); + + g_mutex_unlock (&priv->area_draw_mutex); +} + static gboolean frdp_end_paint (rdpContext *context) { @@ -422,70 +463,75 @@ frdp_end_paint (rdpContext *context) priv = self->priv; if (priv->scaling) { - pos_x = self->priv->offset_x + x * priv->scale; - pos_y = self->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)); + pos_x = self->priv->offset_x + x * priv->scale; + pos_y = self->priv->offset_y + y * priv->scale; + queue_draw_area (self, + 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); + queue_draw_area (self, x, y, w, h); } return TRUE; } +static void +frdp_post_disconnect (freerdp *instance) +{ + FrdpSession *self; + rdpContext *context; + + if (!instance || !instance->context) + return; + + self = ((frdpContext *) instance->context)->self; + + g_signal_handlers_disconnect_by_func (self->priv->display, G_CALLBACK (frdp_session_draw), self); + g_signal_handlers_disconnect_by_func (self->priv->display, G_CALLBACK (frdp_session_configure_event), self); + + context = instance->context; + PubSub_UnsubscribeChannelConnected (context->pubSub, + frdp_on_channel_connected_event_handler); + PubSub_UnsubscribeChannelDisconnected (context->pubSub, + frdp_on_channel_disconnected_event_handler); + gdi_free (instance); +} + static gboolean frdp_post_connect (freerdp *freerdp_session) { FrdpSession *self = ((frdpContext *) freerdp_session->context)->self; - cairo_format_t cairo_format; - rdpGdi *gdi; guint32 color_format; - gint stride; switch (frdp_session_get_best_color_depth (self)) { case 32: - color_format = PIXEL_FORMAT_BGRA32; - cairo_format = CAIRO_FORMAT_ARGB32; + color_format = PIXEL_FORMAT_BGRX32; + self->priv->cairo_format = CAIRO_FORMAT_ARGB32; break; case 24: color_format = PIXEL_FORMAT_BGRX32; - cairo_format = CAIRO_FORMAT_RGB24; + self->priv->cairo_format = CAIRO_FORMAT_RGB24; break; case 16: case 15: color_format = PIXEL_FORMAT_BGR16; - cairo_format = CAIRO_FORMAT_RGB16_565; + self->priv->cairo_format = CAIRO_FORMAT_RGB16_565; break; default: color_format = PIXEL_FORMAT_BGRX32; - cairo_format = CAIRO_FORMAT_RGB16_565; + self->priv->cairo_format = CAIRO_FORMAT_RGB16_565; break; } 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; + freerdp_session->update->DesktopResize = frdp_desktop_resize; - stride = cairo_format_stride_for_width (cairo_format, gdi->width); - self->priv->surface = - cairo_image_surface_create_for_data ((unsigned char*) gdi->primary_buffer, - cairo_format, - gdi->width, - gdi->height, - stride); - - gtk_widget_queue_draw_area (self->priv->display, - 0, - 0, - gdi->width, - gdi->height); + create_cairo_surface (self); return TRUE; } @@ -502,9 +548,13 @@ idle_close (gpointer user_data) self->priv->update_id = 0; } + g_mutex_lock (&self->priv->area_draw_mutex); + g_queue_clear_full (self->priv->area_draw_queue, g_free); + g_mutex_unlock (&self->priv->area_draw_mutex); + g_mutex_clear (&self->priv->area_draw_mutex); + if (self->priv->freerdp_session != NULL) { freerdp_disconnect (self->priv->freerdp_session); - freerdp_context_free (self->priv->freerdp_session); g_clear_pointer (&self->priv->freerdp_session, freerdp_free); } @@ -526,31 +576,49 @@ update (gpointer user_data) DWORD usedHandles; FrdpSessionPrivate *priv; FrdpSession *self = (FrdpSession*) user_data; + GdkRectangle *rectangle; priv = self->priv; + g_mutex_lock (&priv->area_draw_mutex); + + while (priv->area_draw_queue != NULL && !g_queue_is_empty (priv->area_draw_queue)) { + rectangle = g_queue_pop_head (priv->area_draw_queue); + gtk_widget_queue_draw_area (priv->display, rectangle->x, rectangle->y, rectangle->width, rectangle->height); + g_free (rectangle); + } + + g_mutex_unlock (&priv->area_draw_mutex); + + if (freerdp_shall_disconnect (priv->freerdp_session)) { + priv->update_id = 0; + g_idle_add ((GSourceFunc) idle_close, self); + + return FALSE; + } + usedHandles = freerdp_get_event_handles (priv->freerdp_session->context, handles, ARRAYSIZE(handles)); if (usedHandles == 0) { g_warning ("Failed to get FreeRDP event handle"); + priv->update_id = 0; return FALSE; } status = WaitForMultipleObjects (usedHandles, handles, FALSE, SELECT_TIMEOUT); if (status == WAIT_TIMEOUT) - return TRUE; - if (status == WAIT_FAILED) - return FALSE; - - if (!freerdp_check_event_handles (priv->freerdp_session->context)) { - g_warning ("Failed to check FreeRDP file descriptor"); + return TRUE; + if (status == WAIT_FAILED) { + priv->update_id = 0; return FALSE; } - if (freerdp_shall_disconnect (priv->freerdp_session)) { - g_idle_add ((GSourceFunc) idle_close, self); + if (!freerdp_check_event_handles (priv->freerdp_session->context)) { + if (freerdp_get_last_error(priv->freerdp_session->context) == FREERDP_ERROR_SUCCESS) { + g_warning ("Failed to check FreeRDP file descriptor"); + } - return FALSE; + return TRUE; } return TRUE; @@ -560,12 +628,14 @@ static void frdp_session_init_freerdp (FrdpSession *self) { FrdpSessionPrivate *priv = self->priv; - rdpSettings *settings; + rdpSettings *settings; + gchar *build_options; /* 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->PostDisconnect = frdp_post_disconnect; priv->freerdp_session->Authenticate = frdp_authenticate; priv->freerdp_session->VerifyCertificate = frdp_certificate_verify; priv->freerdp_session->VerifyChangedCertificate = frdp_changed_certificate_verify; @@ -594,6 +664,23 @@ frdp_session_init_freerdp (FrdpSession * settings->UseRdpSecurityLayer = FALSE; settings->NegotiateSecurityLayer = TRUE; + + settings->RemoteFxCodec = TRUE; + settings->RedirectClipboard = FALSE; + settings->ColorDepth = 32; + settings->SupportGraphicsPipeline = TRUE; + + build_options = g_ascii_strup (freerdp_get_build_config (), -1); + if (g_strrstr (build_options, "WITH_GFX_H264=ON") != NULL) { + settings->GfxH264 = TRUE; + settings->GfxAVC444 = TRUE; + } else { + settings->GfxH264 = FALSE; + settings->GfxAVC444 = FALSE; + } + g_free (build_options); + + freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); } static void @@ -643,6 +730,9 @@ frdp_session_connect_thread (GTask return; } + gtk_widget_realize (self->priv->display); + create_cairo_surface (self); + g_signal_connect (self->priv->display, "draw", G_CALLBACK (frdp_session_draw), self); g_signal_connect (self->priv->display, "configure-event", @@ -661,21 +751,20 @@ frdp_session_get_property (GObject *o GParamSpec *pspec) { FrdpSession *self = (FrdpSession*) object; - rdpSettings *settings = self->priv->freerdp_session->settings; switch (property_id) { case PROP_HOSTNAME: - g_value_set_string (value, settings->ServerHostname); + g_value_set_string (value, self->priv->hostname); break; case PROP_PORT: - g_value_set_uint (value, settings->ServerPort); + g_value_set_uint (value, self->priv->port); break; case PROP_USERNAME: - g_value_set_string (value, settings->Username); + g_value_set_string (value, self->priv->username); break; case PROP_PASSWORD: - g_value_set_string (value, settings->Password); + g_value_set_string (value, self->priv->password); break; case PROP_DISPLAY: g_value_set_object (value, self->priv->display); @@ -817,6 +906,9 @@ frdp_session_init (FrdpSession *self) { self->priv = frdp_session_get_instance_private (self); + g_mutex_init (&self->priv->area_draw_mutex); + self->priv->area_draw_queue = g_queue_new (); + self->priv->is_connected = FALSE; } @@ -844,7 +936,19 @@ frdp_session_connect (FrdpSession self->priv->port = port; task = g_task_new (self, cancellable, callback, user_data); - g_task_run_in_thread (task, frdp_session_connect_thread); + /* Turn off the asynchronous connection via GTask thread as the FreeRDP + * process then runs in the new thread which makes it hard to cooperate + * with the original thread running UI leading to random race conditions. + * Turn it on again if there will be an async support for connection + * added to FreeRDP. + * The disadvantage is that the application freezes during connection + * for some time. + + g_task_run_in_thread (task, frdp_session_connect_thread); + + */ + + frdp_session_connect_thread (task, self, user_data, cancellable); g_object_unref (task); } --- gnome-connections-41.2/subprojects/gtk-frdp/src/meson.build +++ gnome-connections-41.2/subprojects/gtk-frdp/src/meson.build @@ -40,6 +40,7 @@ gtk_frdp_deps = [ # The 2.0.0-rc4 version is needed at least, but there is no easy way to detect this. dependency('winpr2', version: '>= 2.0.0'), dependency('freerdp2', version: '>= 2.0.0'), + dependency('freerdp-client2', version: '>= 2.0.0'), dependency('gio-2.0', version: '>= 2.50'), dependency('gtk+-3.0'),