diff --git a/src/grd-rdp-pipewire-stream.c b/src/grd-rdp-pipewire-stream.c index 11146635456f02ec26d193dd865dd6b3b714f81b..d61b931b490bbca1d9e4ddccc2dea86d52d8e7f4 100644 --- a/src/grd-rdp-pipewire-stream.c +++ b/src/grd-rdp-pipewire-stream.c @@ -67,18 +67,19 @@ struct _GrdRdpFrame size_t map_size; uint8_t *map; - gboolean has_pointer_data; + GrdRdpPipeWireStream *stream; + GrdRdpFrameReadyCallback callback; + gpointer callback_user_data; +}; + +typedef struct +{ uint8_t *pointer_bitmap; uint16_t pointer_hotspot_x; uint16_t pointer_hotspot_y; uint16_t pointer_width; uint16_t pointer_height; - gboolean pointer_is_hidden; - - GrdRdpPipeWireStream *stream; - GrdRdpFrameReadyCallback callback; - gpointer callback_user_data; -}; +} RdpPointer; typedef struct { @@ -118,10 +119,14 @@ struct _GrdRdpPipeWireStream GrdRdpBufferPool *buffer_pool; - GSource *render_source; + GSource *frame_render_source; GMutex frame_mutex; GrdRdpFrame *pending_frame; + GSource *pointer_render_source; + GMutex pointer_mutex; + RdpPointer *pending_pointer; + struct pw_stream *pipewire_stream; struct spa_hook pipewire_stream_listener; @@ -169,11 +174,17 @@ grd_rdp_frame_unref (GrdRdpFrame *frame) g_assert (!frame->has_map); g_clear_pointer (&frame->buffer, grd_rdp_buffer_release); - g_free (frame->pointer_bitmap); g_free (frame); } } +static void +rdp_pointer_free (RdpPointer *rdp_pointer) +{ + g_clear_pointer (&rdp_pointer->pointer_bitmap, g_free); + g_free (rdp_pointer); +} + void grd_rdp_pipewire_stream_resize (GrdRdpPipeWireStream *stream, GrdRdpVirtualMonitor *virtual_monitor) @@ -199,7 +210,7 @@ grd_rdp_pipewire_stream_resize (GrdRdpPipeWireStream *stream, } static gboolean -do_render (gpointer user_data) +render_frame (gpointer user_data) { GrdRdpPipeWireStream *stream = GRD_RDP_PIPEWIRE_STREAM (user_data); GrdRdpFrame *frame; @@ -223,21 +234,40 @@ do_render (gpointer user_data) grd_session_rdp_maybe_encode_new_frame (stream->session_rdp, stream->rdp_surface); - if (frame->pointer_bitmap) + grd_rdp_frame_unref (frame); + + return G_SOURCE_CONTINUE; +} + +static gboolean +render_mouse_pointer (gpointer user_data) +{ + GrdRdpPipeWireStream *stream = user_data; + g_autoptr (GMutexLocker) locker = NULL; + RdpPointer *rdp_pointer; + + locker = g_mutex_locker_new (&stream->pointer_mutex); + if (!stream->pending_pointer) + return G_SOURCE_CONTINUE; + + rdp_pointer = g_steal_pointer (&stream->pending_pointer); + g_clear_pointer (&locker, g_mutex_locker_free); + + if (rdp_pointer->pointer_bitmap) { grd_session_rdp_update_pointer (stream->session_rdp, - frame->pointer_hotspot_x, - frame->pointer_hotspot_y, - frame->pointer_width, - frame->pointer_height, - g_steal_pointer (&frame->pointer_bitmap)); + rdp_pointer->pointer_hotspot_x, + rdp_pointer->pointer_hotspot_y, + rdp_pointer->pointer_width, + rdp_pointer->pointer_height, + g_steal_pointer (&rdp_pointer->pointer_bitmap)); } - else if (frame->pointer_is_hidden) + else { grd_session_rdp_hide_pointer (stream->session_rdp); } - grd_rdp_frame_unref (frame); + rdp_pointer_free (rdp_pointer); return G_SOURCE_CONTINUE; } @@ -258,13 +288,22 @@ static GSourceFuncs render_source_funcs = }; static void -create_render_source (GrdRdpPipeWireStream *stream, - GMainContext *render_context) +create_render_sources (GrdRdpPipeWireStream *stream, + GMainContext *render_context) { - stream->render_source = g_source_new (&render_source_funcs, sizeof (GSource)); - g_source_set_callback (stream->render_source, do_render, stream, NULL); - g_source_set_ready_time (stream->render_source, -1); - g_source_attach (stream->render_source, render_context); + stream->frame_render_source = g_source_new (&render_source_funcs, + sizeof (GSource)); + g_source_set_callback (stream->frame_render_source, + render_frame, stream, NULL); + g_source_set_ready_time (stream->frame_render_source, -1); + g_source_attach (stream->frame_render_source, render_context); + + stream->pointer_render_source = g_source_new (&render_source_funcs, + sizeof (GSource)); + g_source_set_callback (stream->pointer_render_source, + render_mouse_pointer, stream, NULL); + g_source_set_ready_time (stream->pointer_render_source, -1); + g_source_attach (stream->pointer_render_source, render_context); } static void @@ -405,11 +444,11 @@ on_stream_param_changed (void *user_data, static void process_mouse_pointer_bitmap (GrdRdpPipeWireStream *stream, - struct spa_buffer *buffer, - GrdRdpFrame *frame) + struct spa_buffer *buffer) { struct spa_meta_cursor *spa_meta_cursor; struct spa_meta_bitmap *spa_meta_bitmap; + RdpPointer *rdp_pointer = NULL; GrdPixelFormat format; spa_meta_cursor = spa_buffer_find_meta_data (buffer, SPA_META_Cursor, @@ -432,20 +471,71 @@ process_mouse_pointer_bitmap (GrdRdpPipeWireStream *stream, uint8_t *buf; buf = SPA_MEMBER (spa_meta_bitmap, spa_meta_bitmap->offset, uint8_t); - frame->pointer_bitmap = - g_memdup2 (buf, spa_meta_bitmap->size.height * - spa_meta_bitmap->stride); - frame->pointer_hotspot_x = spa_meta_cursor->hotspot.x; - frame->pointer_hotspot_y = spa_meta_cursor->hotspot.y; - frame->pointer_width = spa_meta_bitmap->size.width; - frame->pointer_height = spa_meta_bitmap->size.height; - frame->has_pointer_data = TRUE; + + rdp_pointer = g_new0 (RdpPointer, 1); + rdp_pointer->pointer_bitmap = + g_memdup2 (buf, spa_meta_bitmap->size.height * spa_meta_bitmap->stride); + rdp_pointer->pointer_hotspot_x = spa_meta_cursor->hotspot.x; + rdp_pointer->pointer_hotspot_y = spa_meta_cursor->hotspot.y; + rdp_pointer->pointer_width = spa_meta_bitmap->size.width; + rdp_pointer->pointer_height = spa_meta_bitmap->size.height; } else if (spa_meta_bitmap) { - frame->pointer_is_hidden = TRUE; - frame->has_pointer_data = TRUE; + rdp_pointer = g_new0 (RdpPointer, 1); + } + + if (rdp_pointer) + { + g_mutex_lock (&stream->pointer_mutex); + g_clear_pointer (&stream->pending_pointer, rdp_pointer_free); + + stream->pending_pointer = rdp_pointer; + g_mutex_unlock (&stream->pointer_mutex); + + g_source_set_ready_time (stream->pointer_render_source, 0); + } +} + +static void +on_frame_ready (GrdRdpPipeWireStream *stream, + GrdRdpFrame *frame, + gboolean success, + gpointer user_data) +{ + struct pw_buffer *buffer = user_data; + GrdRdpFrame *pending_frame; + + g_assert (frame); + + if (frame->has_map) + { + munmap (frame->map, frame->map_size); + frame->has_map = FALSE; + } + + if (!success) + goto out; + + g_mutex_lock (&stream->frame_mutex); + pending_frame = g_steal_pointer (&stream->pending_frame); + if (pending_frame) + { + if (!frame->buffer && pending_frame->buffer) + frame->buffer = g_steal_pointer (&pending_frame->buffer); + + grd_rdp_frame_unref (pending_frame); } + stream->pending_frame = g_steal_pointer (&frame); + g_mutex_unlock (&stream->frame_mutex); + +out: + if (buffer) + pw_stream_queue_buffer (stream->pipewire_stream, buffer); + + g_source_set_ready_time (stream->frame_render_source, 0); + + g_clear_pointer (&frame, grd_rdp_frame_unref); } static void @@ -542,11 +632,12 @@ on_framebuffer_ready (gboolean success, static void process_frame_data (GrdRdpPipeWireStream *stream, - struct spa_buffer *buffer, - GrdRdpFrame *frame) + struct pw_buffer *pw_buffer) { - GrdRdpFrameReadyCallback callback = frame->callback; - gpointer user_data = frame->callback_user_data; + struct spa_buffer *buffer = pw_buffer->buffer; + g_autoptr (GrdRdpFrame) frame = NULL; + GrdRdpFrameReadyCallback callback; + gpointer user_data; uint32_t drm_format; int bpp; int width; @@ -564,6 +655,10 @@ process_frame_data (GrdRdpPipeWireStream *stream, grd_get_spa_format_details (stream->spa_format.format, &drm_format, &bpp); + frame = grd_rdp_frame_new (stream, on_frame_ready, pw_buffer); + callback = frame->callback; + user_data = frame->callback_user_data; + if (buffer->datas[0].type == SPA_DATA_MemFd) { GrdSession *session = GRD_SESSION (stream->session_rdp); @@ -584,7 +679,7 @@ process_frame_data (GrdRdpPipeWireStream *stream, if (map == MAP_FAILED) { g_warning ("Failed to mmap buffer: %s", g_strerror (errno)); - callback (stream, g_steal_pointer (&frame), TRUE, user_data); + callback (stream, g_steal_pointer (&frame), FALSE, user_data); return; } src_data = SPA_MEMBER (map, buffer->datas[0].mapoffset, uint8_t); @@ -741,69 +836,10 @@ process_frame_data (GrdRdpPipeWireStream *stream, } } -static void -take_pointer_data_from (GrdRdpFrame *src_frame, - GrdRdpFrame *dst_frame) -{ - g_assert (!dst_frame->pointer_bitmap); - dst_frame->pointer_bitmap = g_steal_pointer (&src_frame->pointer_bitmap); - - dst_frame->pointer_hotspot_x = src_frame->pointer_hotspot_x; - dst_frame->pointer_hotspot_y = src_frame->pointer_hotspot_y; - dst_frame->pointer_width = src_frame->pointer_width; - dst_frame->pointer_height = src_frame->pointer_height; - dst_frame->pointer_is_hidden = src_frame->pointer_is_hidden; - dst_frame->has_pointer_data = TRUE; -} - -static void -on_frame_ready (GrdRdpPipeWireStream *stream, - GrdRdpFrame *frame, - gboolean success, - gpointer user_data) -{ - struct pw_buffer *buffer = user_data; - GrdRdpFrame *pending_frame; - - g_assert (frame); - - if (frame->has_map) - { - munmap (frame->map, frame->map_size); - frame->has_map = FALSE; - } - - if (!success) - goto out; - - g_mutex_lock (&stream->frame_mutex); - pending_frame = g_steal_pointer (&stream->pending_frame); - if (pending_frame) - { - if (!frame->buffer && pending_frame->buffer) - frame->buffer = g_steal_pointer (&pending_frame->buffer); - if (!frame->has_pointer_data && pending_frame->has_pointer_data) - take_pointer_data_from (pending_frame, frame); - - grd_rdp_frame_unref (pending_frame); - } - stream->pending_frame = g_steal_pointer (&frame); - g_mutex_unlock (&stream->frame_mutex); - -out: - if (buffer) - pw_stream_queue_buffer (stream->pipewire_stream, buffer); - - g_source_set_ready_time (stream->render_source, 0); - - g_clear_pointer (&frame, grd_rdp_frame_unref); -} - static void on_stream_process (void *user_data) { GrdRdpPipeWireStream *stream = GRD_RDP_PIPEWIRE_STREAM (user_data); - g_autoptr (GrdRdpFrame) frame = NULL; struct pw_buffer *last_pointer_buffer = NULL; struct pw_buffer *last_frame_buffer = NULL; struct pw_buffer *next_buffer; @@ -848,25 +884,16 @@ on_stream_process (void *user_data) if (!last_pointer_buffer && !last_frame_buffer) return; - frame = grd_rdp_frame_new (stream, on_frame_ready, last_frame_buffer); if (last_pointer_buffer) { - process_mouse_pointer_bitmap (stream, last_pointer_buffer->buffer, frame); + process_mouse_pointer_bitmap (stream, last_pointer_buffer->buffer); if (last_pointer_buffer != last_frame_buffer) pw_stream_queue_buffer (stream->pipewire_stream, last_pointer_buffer); } - if (!last_frame_buffer) - { - GrdRdpFrameReadyCallback callback = frame->callback; - gpointer callback_user_data = frame->callback_user_data; - - callback (stream, g_steal_pointer (&frame), TRUE, callback_user_data); - return; - } + return; - process_frame_data (stream, last_frame_buffer->buffer, - g_steal_pointer (&frame)); + process_frame_data (stream, last_frame_buffer); } static const struct pw_stream_events stream_events = { @@ -1074,7 +1101,7 @@ grd_rdp_pipewire_stream_new (GrdSessionRdp *session_rdp, pw_init (NULL, NULL); - create_render_source (stream, render_context); + create_render_sources (stream, render_context); pipewire_source = grd_attached_pipewire_source_new ("RDP", error); if (!pipewire_source) @@ -1143,18 +1170,25 @@ grd_rdp_pipewire_stream_finalize (GObject *object) g_clear_pointer (&stream->pipewire_source, g_source_unref); } - if (stream->render_source) + if (stream->pointer_render_source) + { + g_source_destroy (stream->pointer_render_source); + g_clear_pointer (&stream->pointer_render_source, g_source_unref); + } + if (stream->frame_render_source) { - g_source_destroy (stream->render_source); - g_clear_pointer (&stream->render_source, g_source_unref); + g_source_destroy (stream->frame_render_source); + g_clear_pointer (&stream->frame_render_source, g_source_unref); } grd_rdp_damage_detector_invalidate_surface (stream->rdp_surface->detector); + g_clear_pointer (&stream->pending_pointer, rdp_pointer_free); g_clear_pointer (&stream->pending_frame, grd_rdp_frame_unref); release_all_buffers (stream); g_clear_object (&stream->buffer_pool); + g_mutex_clear (&stream->pointer_mutex); g_mutex_clear (&stream->frame_mutex); pw_deinit (); @@ -1166,6 +1200,7 @@ static void grd_rdp_pipewire_stream_init (GrdRdpPipeWireStream *stream) { g_mutex_init (&stream->frame_mutex); + g_mutex_init (&stream->pointer_mutex); } static void diff --git a/src/grd-vnc-pipewire-stream.c b/src/grd-vnc-pipewire-stream.c index bd789df38570a1f170645995164307410110a0d7..36a3c6ff8c318392fd6ea4985fa12ac4d25cdd5d 100644 --- a/src/grd-vnc-pipewire-stream.c +++ b/src/grd-vnc-pipewire-stream.c @@ -55,16 +55,20 @@ struct _GrdVncFrame gatomicrefcount refcount; void *data; - rfbCursorPtr rfb_cursor; - gboolean cursor_moved; - int cursor_x; - int cursor_y; GrdVncPipeWireStream *stream; GrdVncFrameReadyCallback callback; gpointer callback_user_data; }; +typedef struct +{ + rfbCursorPtr rfb_cursor; + gboolean cursor_moved; + int cursor_x; + int cursor_y; +} VncPointer; + struct _GrdVncPipeWireStream { GObject parent; @@ -81,6 +85,10 @@ struct _GrdVncPipeWireStream GrdVncFrame *pending_frame; GSource *pending_frame_source; + GMutex pointer_mutex; + VncPointer *pending_pointer; + GSource *pending_pointer_source; + struct pw_stream *pipewire_stream; struct spa_hook pipewire_stream_listener; @@ -96,6 +104,13 @@ static void grd_vnc_frame_unref (GrdVncFrame *frame); G_DEFINE_AUTOPTR_CLEANUP_FUNC (GrdVncFrame, grd_vnc_frame_unref) +static void +vnc_pointer_free (VncPointer *vnc_pointer) +{ + g_clear_pointer (&vnc_pointer->rfb_cursor, rfbFreeCursor); + g_free (vnc_pointer); +} + void grd_vnc_pipewire_stream_resize (GrdVncPipeWireStream *stream, GrdVncVirtualMonitor *virtual_monitor) @@ -237,13 +252,12 @@ grd_vnc_frame_unref (GrdVncFrame *frame) if (g_atomic_ref_count_dec (&frame->refcount)) { g_free (frame->data); - g_clear_pointer (&frame->rfb_cursor, rfbFreeCursor); g_free (frame); } } static gboolean -do_render (gpointer user_data) +render_frame (gpointer user_data) { GrdVncPipeWireStream *stream = GRD_VNC_PIPEWIRE_STREAM (user_data); GrdVncFrame *frame; @@ -261,19 +275,6 @@ do_render (gpointer user_data) return G_SOURCE_CONTINUE; } - if (frame->rfb_cursor) - { - grd_session_vnc_set_cursor (stream->session, - g_steal_pointer (&frame->rfb_cursor)); - } - - if (frame->cursor_moved) - { - grd_session_vnc_move_cursor (stream->session, - frame->cursor_x, - frame->cursor_y); - } - if (frame->data) { grd_session_vnc_take_buffer (stream->session, @@ -289,10 +290,43 @@ do_render (gpointer user_data) return G_SOURCE_CONTINUE; } +static gboolean +render_mouse_pointer (gpointer user_data) +{ + GrdVncPipeWireStream *stream = user_data; + g_autoptr (GMutexLocker) locker = NULL; + VncPointer *vnc_pointer; + + locker = g_mutex_locker_new (&stream->pointer_mutex); + if (!stream->pending_pointer) + return G_SOURCE_CONTINUE; + + vnc_pointer = g_steal_pointer (&stream->pending_pointer); + g_clear_pointer (&locker, g_mutex_locker_free); + + if (vnc_pointer->rfb_cursor) + { + grd_session_vnc_set_cursor (stream->session, + g_steal_pointer (&vnc_pointer->rfb_cursor)); + } + if (vnc_pointer->cursor_moved) + { + grd_session_vnc_move_cursor (stream->session, + vnc_pointer->cursor_x, + vnc_pointer->cursor_y); + } + + grd_session_vnc_flush (stream->session); + + vnc_pointer_free (vnc_pointer); + + return G_SOURCE_CONTINUE; +} + static void -process_mouse_pointer_bitmap (GrdVncPipeWireStream *stream, - struct spa_buffer *buffer, - GrdVncFrame *frame) +process_mouse_pointer_bitmap (GrdVncPipeWireStream *stream, + struct spa_buffer *buffer, + VncPointer **vnc_pointer) { struct spa_meta_cursor *spa_meta_cursor; struct spa_meta_bitmap *spa_meta_bitmap; @@ -327,12 +361,54 @@ process_mouse_pointer_bitmap (GrdVncPipeWireStream *stream, rfb_cursor->xhot = spa_meta_cursor->hotspot.x; rfb_cursor->yhot = spa_meta_cursor->hotspot.y; - frame->rfb_cursor = rfb_cursor; + if (!(*vnc_pointer)) + *vnc_pointer = g_new0 (VncPointer, 1); + (*vnc_pointer)->rfb_cursor = rfb_cursor; } else if (spa_meta_bitmap) { - frame->rfb_cursor = grd_vnc_create_empty_cursor (1, 1); + if (!(*vnc_pointer)) + *vnc_pointer = g_new0 (VncPointer, 1); + (*vnc_pointer)->rfb_cursor = grd_vnc_create_empty_cursor (1, 1); + } +} + +static void +on_frame_ready (GrdVncPipeWireStream *stream, + GrdVncFrame *frame, + gboolean success, + gpointer user_data) +{ + GrdVncFrame *pending_frame; + struct pw_buffer *buffer = user_data; + + g_assert (frame); + + if (!success) + goto out; + + g_mutex_lock (&stream->frame_mutex); + + pending_frame = g_steal_pointer (&stream->pending_frame); + if (pending_frame) + { + if (!frame->data && pending_frame->data) + frame->data = g_steal_pointer (&pending_frame->data); + + grd_vnc_frame_unref (pending_frame); } + + stream->pending_frame = g_steal_pointer (&frame); + + g_mutex_unlock (&stream->frame_mutex); + +out: + if (buffer) + pw_stream_queue_buffer (stream->pipewire_stream, buffer); + + g_source_set_ready_time (stream->pending_frame_source, 0); + + g_clear_pointer (&frame, grd_vnc_frame_unref); } static void @@ -369,11 +445,12 @@ on_dma_buf_downloaded (gboolean success, static void process_frame_data (GrdVncPipeWireStream *stream, - struct spa_buffer *buffer, - GrdVncFrame *frame) + struct pw_buffer *pw_buffer) { - GrdVncFrameReadyCallback callback = frame->callback; - gpointer user_data = frame->callback_user_data; + struct spa_buffer *buffer = pw_buffer->buffer; + g_autoptr (GrdVncFrame) frame = NULL; + GrdVncFrameReadyCallback callback; + gpointer user_data; int dst_stride; uint32_t drm_format; int bpp; @@ -389,6 +466,10 @@ process_frame_data (GrdVncPipeWireStream *stream, grd_get_spa_format_details (stream->spa_format.format, &drm_format, &bpp); + frame = grd_vnc_frame_new (stream, on_frame_ready, pw_buffer); + callback = frame->callback; + user_data = frame->callback_user_data; + if (buffer->datas[0].type == SPA_DATA_MemFd) { size_t size; @@ -473,66 +554,20 @@ process_frame_data (GrdVncPipeWireStream *stream, } static gboolean -pending_frame_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) +render_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) { g_source_set_ready_time (source, -1); return callback (user_data); } -static GSourceFuncs pending_frame_source_funcs = +static GSourceFuncs render_source_funcs = { - .dispatch = pending_frame_source_dispatch, + .dispatch = render_source_dispatch, }; -static void -on_frame_ready (GrdVncPipeWireStream *stream, - GrdVncFrame *frame, - gboolean success, - gpointer user_data) -{ - GrdVncFrame *pending_frame; - struct pw_buffer *buffer = user_data; - - g_assert (frame); - - if (!success) - goto out; - - g_mutex_lock (&stream->frame_mutex); - - pending_frame = g_steal_pointer (&stream->pending_frame); - if (pending_frame) - { - if (!frame->data && pending_frame->data) - frame->data = g_steal_pointer (&pending_frame->data); - if (!frame->rfb_cursor && pending_frame->rfb_cursor) - frame->rfb_cursor = g_steal_pointer (&pending_frame->rfb_cursor); - if (!frame->cursor_moved && pending_frame->cursor_moved) - { - frame->cursor_x = pending_frame->cursor_x; - frame->cursor_y = pending_frame->cursor_y; - frame->cursor_moved = TRUE; - } - - grd_vnc_frame_unref (pending_frame); - } - - stream->pending_frame = g_steal_pointer (&frame); - - g_mutex_unlock (&stream->frame_mutex); - -out: - if (buffer) - pw_stream_queue_buffer (stream->pipewire_stream, buffer); - - g_source_set_ready_time (stream->pending_frame_source, 0); - - g_clear_pointer (&frame, grd_vnc_frame_unref); -} - static void maybe_consume_pointer_position (struct pw_buffer *buffer, gboolean *cursor_moved, @@ -559,6 +594,7 @@ on_stream_process (void *user_data) struct pw_buffer *last_pointer_buffer = NULL; struct pw_buffer *last_frame_buffer = NULL; struct pw_buffer *next_buffer; + VncPointer *vnc_pointer = NULL; gboolean cursor_moved = FALSE; int cursor_x = 0; int cursor_y = 0; @@ -606,29 +642,35 @@ on_stream_process (void *user_data) if (!last_pointer_buffer && !last_frame_buffer && !cursor_moved) return; - frame = grd_vnc_frame_new (stream, on_frame_ready, last_frame_buffer); - frame->cursor_moved = cursor_moved; - frame->cursor_x = cursor_x; - frame->cursor_y = cursor_y; + if (cursor_moved) + { + vnc_pointer = g_new0 (VncPointer, 1); + vnc_pointer->cursor_moved = cursor_moved; + vnc_pointer->cursor_x = cursor_x; + vnc_pointer->cursor_y = cursor_y; + } if (last_pointer_buffer) { - process_mouse_pointer_bitmap (stream, last_pointer_buffer->buffer, frame); + process_mouse_pointer_bitmap (stream, last_pointer_buffer->buffer, + &vnc_pointer); if (last_pointer_buffer != last_frame_buffer) pw_stream_queue_buffer (stream->pipewire_stream, last_pointer_buffer); } - - if (!last_frame_buffer) + if (vnc_pointer) { - GrdVncFrameReadyCallback callback = frame->callback; - gpointer callback_user_data = frame->callback_user_data; + g_mutex_lock (&stream->pointer_mutex); + g_clear_pointer (&stream->pending_pointer, vnc_pointer_free); - callback (stream, g_steal_pointer (&frame), TRUE, callback_user_data); - return; + stream->pending_pointer = vnc_pointer; + g_mutex_unlock (&stream->pointer_mutex); + + g_source_set_ready_time (stream->pending_pointer_source, 0); } + if (!last_frame_buffer) + return; - process_frame_data (stream, last_frame_buffer->buffer, - g_steal_pointer (&frame)); + process_frame_data (stream, last_frame_buffer); } static const struct pw_stream_events stream_events = { @@ -850,9 +892,15 @@ grd_vnc_pipewire_stream_new (GrdSessionVnc *session_vnc, return NULL; } - source = g_source_new (&pending_frame_source_funcs, sizeof (GSource)); + source = g_source_new (&render_source_funcs, sizeof (GSource)); stream->pending_frame_source = source; - g_source_set_callback (source, do_render, stream, NULL); + g_source_set_callback (source, render_frame, stream, NULL); + g_source_attach (source, NULL); + g_source_unref (source); + + source = g_source_new (&render_source_funcs, sizeof (GSource)); + stream->pending_pointer_source = source; + g_source_set_callback (source, render_mouse_pointer, stream, NULL); g_source_attach (source, NULL); g_source_unref (source); @@ -904,6 +952,7 @@ grd_vnc_pipewire_stream_finalize (GObject *object) g_clear_pointer (&stream->pipewire_core, pw_core_disconnect); g_clear_pointer (&stream->pipewire_context, pw_context_destroy); + g_clear_pointer (&stream->pending_pointer_source, g_source_destroy); g_clear_pointer (&stream->pending_frame_source, g_source_destroy); if (stream->pipewire_source) { @@ -911,8 +960,10 @@ grd_vnc_pipewire_stream_finalize (GObject *object) g_clear_pointer (&stream->pipewire_source, g_source_unref); } + g_clear_pointer (&stream->pending_pointer, vnc_pointer_free); g_clear_pointer (&stream->pending_frame, grd_vnc_frame_unref); + g_mutex_clear (&stream->pointer_mutex); g_mutex_clear (&stream->frame_mutex); pw_deinit (); @@ -924,6 +975,7 @@ static void grd_vnc_pipewire_stream_init (GrdVncPipeWireStream *stream) { g_mutex_init (&stream->frame_mutex); + g_mutex_init (&stream->pointer_mutex); } static void