[Spice-commits] 7 commits - server/cursor-channel.cpp server/cursor-channel.h server/dcc.cpp server/dcc-send.cpp server/display-channel.cpp server/display-channel.h server/display-channel-private.h server/image-encoders.cpp server/Makefile.am server/meson.build server/red-parse-qxl.cpp server/red-parse-qxl.h server/red-record-qxl.c server/red-record-qxl.cpp server/red-stream-device.cpp server/red-worker.cpp server/tests server/tree.cpp server/utils.hpp server/video-stream.cpp

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Aug 4 12:03:19 UTC 2021


 server/Makefile.am                |    2 
 server/cursor-channel.cpp         |   32 +---
 server/cursor-channel.h           |    2 
 server/dcc-send.cpp               |   68 ++++-----
 server/dcc.cpp                    |    2 
 server/display-channel-private.h  |    4 
 server/display-channel.cpp        |   46 ++----
 server/display-channel.h          |   14 +-
 server/image-encoders.cpp         |    8 -
 server/meson.build                |    2 
 server/red-parse-qxl.cpp          |  262 ++++++++++----------------------------
 server/red-parse-qxl.h            |   87 +++++-------
 server/red-stream-device.cpp      |   21 +--
 server/red-worker.cpp             |   52 ++-----
 server/tests/Makefile.am          |    1 
 server/tests/meson.build          |    2 
 server/tests/test-qxl-parsing.cpp |   38 ++---
 server/tree.cpp                   |    2 
 server/utils.hpp                  |   62 ++++++++
 server/video-stream.cpp           |    6 
 20 files changed, 307 insertions(+), 406 deletions(-)

New commits:
commit 708cd97212e5f39ffd971123a45eee87d3d24566
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 18:33:42 2020 +0100

    red-parse-qxl: Encapsulate QXL resource management
    
    Reuse code.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-parse-qxl.cpp b/server/red-parse-qxl.cpp
index 25675e7f..87b6448d 100644
--- a/server/red-parse-qxl.cpp
+++ b/server/red-parse-qxl.cpp
@@ -77,6 +77,22 @@ static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
 }
 #endif
 
+template <typename T>
+inline RedQXLResource<T>::~RedQXLResource()
+{
+    if (qxl) {
+        red_qxl_release_resource(qxl, release_info_ext);
+    }
+}
+
+template <typename T>
+inline void RedQXLResource<T>::set_resource(QXLInstance *qxl_instance, QXLReleaseInfo *info, uint32_t group_id)
+{
+    qxl = qxl_instance;
+    release_info_ext.info = info;
+    release_info_ext.group_id = group_id;
+}
+
 static inline uint32_t color_16_to_32(uint32_t color)
 {
     uint32_t ret;
@@ -1026,9 +1042,7 @@ static bool red_get_native_drawable(QXLInstance *qxl_instance, RedMemSlotInfo *s
     if (qxl == nullptr) {
         return false;
     }
-    red->qxl = qxl_instance;
-    red->release_info_ext.info     = &qxl->release_info;
-    red->release_info_ext.group_id = group_id;
+    red->set_resource(qxl_instance, &qxl->release_info, group_id);
 
     red_get_rect_ptr(&red->bbox, &qxl->bbox);
     red_get_clip_ptr(slots, group_id, &red->clip, &qxl->clip);
@@ -1106,9 +1120,7 @@ static bool red_get_compat_drawable(QXLInstance *qxl_instance, RedMemSlotInfo *s
     if (qxl == nullptr) {
         return false;
     }
-    red->qxl = qxl_instance;
-    red->release_info_ext.info     = &qxl->release_info;
-    red->release_info_ext.group_id = group_id;
+    red->set_resource(qxl_instance, &qxl->release_info, group_id);
 
     red_get_rect_ptr(&red->bbox, &qxl->bbox);
     red_get_clip_ptr(slots, group_id, &red->clip, &qxl->clip);
@@ -1240,9 +1252,6 @@ RedDrawable::~RedDrawable()
         red_put_whiteness(&u.whiteness);
         break;
     }
-    if (qxl != nullptr) {
-        red_qxl_release_resource(qxl, release_info_ext);
-    }
 }
 
 red::shared_ptr<RedDrawable>
@@ -1267,9 +1276,7 @@ static bool red_get_update_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
     if (qxl == nullptr) {
         return false;
     }
-    red->qxl = qxl_instance;
-    red->release_info_ext.info     = &qxl->release_info;
-    red->release_info_ext.group_id = group_id;
+    red->set_resource(qxl_instance, &qxl->release_info, group_id);
 
     red_get_rect_ptr(&red->area, &qxl->area);
     red->update_id  = qxl->update_id;
@@ -1277,12 +1284,7 @@ static bool red_get_update_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
     return true;
 }
 
-RedUpdateCmd::~RedUpdateCmd()
-{
-    if (qxl != nullptr) {
-        red_qxl_release_resource(qxl, release_info_ext);
-    }
-}
+RedUpdateCmd::~RedUpdateCmd() = default;
 
 red::shared_ptr<const RedUpdateCmd>
 red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
@@ -1315,9 +1317,7 @@ static bool red_get_message(QXLInstance *qxl_instance, RedMemSlotInfo *slots, in
     if (qxl == nullptr) {
         return false;
     }
-    red->qxl = qxl_instance;
-    red->release_info_ext.info      = &qxl->release_info;
-    red->release_info_ext.group_id  = group_id;
+    red->set_resource(qxl_instance, &qxl->release_info, group_id);
     red->data                       = qxl->data;
     memslot_id = memslot_get_id(slots, addr+sizeof(*qxl));
     len = memslot_max_size_virt(slots, ((intptr_t) qxl)+sizeof(*qxl), memslot_id, group_id);
@@ -1330,12 +1330,7 @@ static bool red_get_message(QXLInstance *qxl_instance, RedMemSlotInfo *slots, in
     return true;
 }
 
-RedMessage::~RedMessage()
-{
-    if (qxl != nullptr) {
-        red_qxl_release_resource(qxl, release_info_ext);
-    }
-}
+RedMessage::~RedMessage() = default;
 
 red::shared_ptr<const RedMessage>
 red_message_new(QXLInstance *qxl, RedMemSlotInfo *slots,
@@ -1403,9 +1398,7 @@ static bool red_get_surface_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots
     if (qxl == nullptr) {
         return false;
     }
-    red->qxl = qxl_instance;
-    red->release_info_ext.info      = &qxl->release_info;
-    red->release_info_ext.group_id  = group_id;
+    red->set_resource(qxl_instance, &qxl->release_info, group_id);
 
     red->surface_id = qxl->surface_id;
     red->type       = qxl->type;
@@ -1434,12 +1427,7 @@ static bool red_get_surface_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots
     return true;
 }
 
-RedSurfaceCmd::~RedSurfaceCmd()
-{
-    if (qxl) {
-        red_qxl_release_resource(qxl, release_info_ext);
-    }
-}
+RedSurfaceCmd::~RedSurfaceCmd() = default;
 
 red::shared_ptr<const RedSurfaceCmd>
 red_surface_cmd_new(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
@@ -1513,9 +1501,7 @@ static bool red_get_cursor_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
     if (qxl == nullptr) {
         return false;
     }
-    red->qxl = qxl_instance;
-    red->release_info_ext.info      = &qxl->release_info;
-    red->release_info_ext.group_id  = group_id;
+    red->set_resource(qxl_instance, &qxl->release_info, group_id);
 
     red->type = qxl->type;
     switch (red->type) {
@@ -1553,7 +1539,4 @@ RedCursorCmd::~RedCursorCmd()
         red_put_cursor(&u.set.shape);
         break;
     }
-    if (qxl) {
-        red_qxl_release_resource(qxl, release_info_ext);
-    }
 }
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index 7ed0cbd9..cbea4504 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -27,10 +27,17 @@
 
 #include "push-visibility.h"
 
-struct RedDrawable final: public red::simple_ptr_counted<RedDrawable> {
-    ~RedDrawable();
-    QXLInstance *qxl;
+template <typename T>
+struct RedQXLResource: public red::simple_ptr_counted<T> {
+    ~RedQXLResource();
+    void set_resource(QXLInstance *qxl, QXLReleaseInfo *info, uint32_t group_id);
+private:
+    QXLInstance *qxl = nullptr;
     QXLReleaseInfoExt release_info_ext;
+};
+
+struct RedDrawable final: public RedQXLResource<RedDrawable> {
+    ~RedDrawable();
     uint32_t surface_id;
     uint8_t effect;
     uint8_t type;
@@ -62,19 +69,15 @@ struct RedDrawable final: public red::simple_ptr_counted<RedDrawable> {
     } u;
 };
 
-struct RedUpdateCmd final: public red::simple_ptr_counted<RedUpdateCmd> {
+struct RedUpdateCmd final: public RedQXLResource<RedUpdateCmd> {
     ~RedUpdateCmd();
-    QXLInstance *qxl;
-    QXLReleaseInfoExt release_info_ext;
     SpiceRect area;
     uint32_t update_id;
     uint32_t surface_id;
 };
 
-struct RedMessage final: public red::simple_ptr_counted<RedMessage> {
+struct RedMessage final: public RedQXLResource<RedMessage> {
     ~RedMessage();
-    QXLInstance *qxl;
-    QXLReleaseInfoExt release_info_ext;
     int len;
     uint8_t *data;
 };
@@ -87,10 +90,8 @@ typedef struct RedSurfaceCreate {
     uint8_t *data;
 } RedSurfaceCreate;
 
-struct RedSurfaceCmd final: public red::simple_ptr_counted<RedSurfaceCmd> {
+struct RedSurfaceCmd final: public RedQXLResource<RedSurfaceCmd> {
     ~RedSurfaceCmd();
-    QXLInstance *qxl;
-    QXLReleaseInfoExt release_info_ext;
     uint32_t surface_id;
     uint8_t type;
     uint32_t flags;
@@ -99,10 +100,8 @@ struct RedSurfaceCmd final: public red::simple_ptr_counted<RedSurfaceCmd> {
     } u;
 };
 
-struct RedCursorCmd final: public red::simple_ptr_counted<RedCursorCmd> {
+struct RedCursorCmd final: public RedQXLResource<RedCursorCmd> {
     ~RedCursorCmd();
-    QXLInstance *qxl;
-    QXLReleaseInfoExt release_info_ext;
     uint8_t type;
     union {
         struct {
commit b6aa5798b7ee1754bf2f375db09eae8dd162c7fb
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 17:39:14 2020 +0100

    red-parse-qxl: Use a base reference class for RedDrawable
    
    Don't code manually reference counting for this structure
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp
index 4d1558a9..b43b7a1f 100644
--- a/server/dcc-send.cpp
+++ b/server/dcc-send.cpp
@@ -530,7 +530,7 @@ static void marshall_qxl_draw_fill(DisplayChannelClient *dcc,
                                    RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceFill fill;
@@ -561,7 +561,7 @@ static void surface_lossy_region_update(DisplayChannelClient *dcc,
     }
 
     surface_lossy_region = &dcc->priv->surface_client_lossy_region[item->surface_id];
-    drawable = item->red_drawable;
+    drawable = item->red_drawable.get();
 
     if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS ) {
         QRegion clip_rgn;
@@ -636,7 +636,7 @@ static bool drawable_depends_on_areas(Drawable *drawable, int surface_ids[],
     int drawable_has_shadow;
     SpiceRect shadow_rect = {0, 0, 0, 0};
 
-    red_drawable = drawable->red_drawable;
+    red_drawable = drawable->red_drawable.get();
     drawable_has_shadow = has_shadow(red_drawable);
 
     if (drawable_has_shadow) {
@@ -737,7 +737,7 @@ static void red_add_lossless_drawable_dependencies(DisplayChannelClient *dcc,
                                                    int num_deps)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int sync_rendered = FALSE;
     int i;
 
@@ -803,7 +803,7 @@ static void red_lossy_marshall_qxl_draw_fill(DisplayChannelClient *dcc,
                                              RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
 
     int dest_allowed_lossy = FALSE;
     int dest_is_lossy = FALSE;
@@ -860,7 +860,7 @@ static FillBitsType red_marshall_qxl_draw_opaque(DisplayChannelClient *dcc,
                                                  int src_allowed_lossy)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
@@ -892,7 +892,7 @@ static void red_lossy_marshall_qxl_draw_opaque(DisplayChannelClient *dcc,
                                                RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
 
     int src_allowed_lossy;
     int rop;
@@ -956,7 +956,7 @@ static FillBitsType red_marshall_qxl_draw_copy(DisplayChannelClient *dcc,
                                                int src_allowed_lossy)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceCopy copy;
@@ -981,7 +981,7 @@ static void red_lossy_marshall_qxl_draw_copy(DisplayChannelClient *dcc,
                                              RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int has_mask = !!drawable->u.copy.mask.bitmap;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -1005,7 +1005,7 @@ static void red_marshall_qxl_draw_transparent(DisplayChannelClient *dcc,
                                               RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *src_bitmap_out;
     SpiceTransparent transparent;
 
@@ -1023,7 +1023,7 @@ static void red_lossy_marshall_qxl_draw_transparent(DisplayChannelClient *dcc,
                                                     RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int src_is_lossy;
     BitmapData src_bitmap_data;
 
@@ -1051,7 +1051,7 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(DisplayChannelClient *dcc,
                                                       int src_allowed_lossy)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *src_bitmap_out;
     SpiceAlphaBlend alpha_blend;
     FillBitsType src_send_type;
@@ -1073,7 +1073,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(DisplayChannelClient *dcc,
                                                     RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int src_is_lossy;
     BitmapData src_bitmap_data;
     FillBitsType src_send_type;
@@ -1099,7 +1099,7 @@ static void red_marshall_qxl_copy_bits(RedChannelClient *rcc,
                                        RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpicePoint copy_bits;
 
     rcc->init_send_data(SPICE_MSG_DISPLAY_COPY_BITS);
@@ -1114,7 +1114,7 @@ static void red_lossy_marshall_qxl_copy_bits(DisplayChannelClient *dcc,
                                              RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceRect src_rect;
     int horz_offset;
     int vert_offset;
@@ -1142,7 +1142,7 @@ static void red_marshall_qxl_draw_blend(DisplayChannelClient *dcc,
                                         RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceBlend blend;
@@ -1165,7 +1165,7 @@ static void red_lossy_marshall_qxl_draw_blend(DisplayChannelClient *dcc,
                                               RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int src_is_lossy;
     BitmapData src_bitmap_data;
     int dest_is_lossy;
@@ -1206,7 +1206,7 @@ static void red_marshall_qxl_draw_blackness(DisplayChannelClient *dcc,
                                             RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *mask_bitmap_out;
     SpiceBlackness blackness;
 
@@ -1226,7 +1226,7 @@ static void red_lossy_marshall_qxl_draw_blackness(DisplayChannelClient *dcc,
                                                   RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int has_mask = !!drawable->u.blackness.mask.bitmap;
 
     red_marshall_qxl_draw_blackness(dcc, base_marshaller, dpi);
@@ -1239,7 +1239,7 @@ static void red_marshall_qxl_draw_whiteness(DisplayChannelClient *dcc,
                                             RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *mask_bitmap_out;
     SpiceWhiteness whiteness;
 
@@ -1259,7 +1259,7 @@ static void red_lossy_marshall_qxl_draw_whiteness(DisplayChannelClient *dcc,
                                                   RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int has_mask = !!drawable->u.whiteness.mask.bitmap;
 
     red_marshall_qxl_draw_whiteness(dcc, base_marshaller, dpi);
@@ -1271,7 +1271,7 @@ static void red_marshall_qxl_draw_inverse(DisplayChannelClient *dcc,
                                           SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *mask_bitmap_out;
     SpiceInvers inverse;
 
@@ -1298,7 +1298,7 @@ static void red_marshall_qxl_draw_rop3(DisplayChannelClient *dcc,
                                        RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceRop3 rop3;
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *brush_pat_out;
@@ -1326,7 +1326,7 @@ static void red_lossy_marshall_qxl_draw_rop3(DisplayChannelClient *dcc,
                                              RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int src_is_lossy;
     BitmapData src_bitmap_data;
     int brush_is_lossy;
@@ -1380,7 +1380,7 @@ static void red_marshall_qxl_draw_composite(DisplayChannelClient *dcc,
                                             RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceComposite composite;
@@ -1404,7 +1404,7 @@ static void red_lossy_marshall_qxl_draw_composite(DisplayChannelClient *dcc,
                                                   RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int src_is_lossy;
     BitmapData src_bitmap_data;
     int mask_is_lossy;
@@ -1459,7 +1459,7 @@ static void red_marshall_qxl_draw_stroke(DisplayChannelClient *dcc,
                                          RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceStroke stroke;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *style_out;
@@ -1483,7 +1483,7 @@ static void red_lossy_marshall_qxl_draw_stroke(DisplayChannelClient *dcc,
                                                RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int brush_is_lossy;
     BitmapData brush_bitmap_data;
     int dest_is_lossy = FALSE;
@@ -1537,7 +1537,7 @@ static void red_marshall_qxl_draw_text(DisplayChannelClient *dcc,
                                        RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     SpiceText text;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *back_brush_pat_out;
@@ -1563,7 +1563,7 @@ static void red_lossy_marshall_qxl_draw_text(DisplayChannelClient *dcc,
                                              RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
     int fg_is_lossy;
     BitmapData fg_bitmap_data;
     int bg_is_lossy;
@@ -1669,7 +1669,7 @@ static bool red_marshall_stream_data(DisplayChannelClient *dcc,
                                              frame_mm_time,
                                              &copy->src_bitmap->u.bitmap,
                                              &copy->src_area, stream->top_down,
-                                             drawable->red_drawable,
+                                             drawable->red_drawable.get(),
                                              &outbuf);
     switch (ret) {
     case VIDEO_ENCODER_FRAME_DROP:
@@ -2019,7 +2019,7 @@ static void marshall_lossless_qxl_drawable(DisplayChannelClient *dcc,
                                            RedDrawablePipeItem *dpi)
 {
     Drawable *item = dpi->drawable;
-    RedDrawable *drawable = item->red_drawable;
+    RedDrawable *drawable = item->red_drawable.get();
 
     switch (drawable->type) {
     case QXL_DRAW_FILL:
@@ -2117,7 +2117,7 @@ static void marshall_stream_start(DisplayChannelClient *dcc,
     stream_create.dest = stream->dest_area;
 
     if (stream->current) {
-        RedDrawable *red_drawable = stream->current->red_drawable;
+        RedDrawable *red_drawable = stream->current->red_drawable.get();
         stream_create.clip = red_drawable->clip;
     } else {
         stream_create.clip.type = SPICE_CLIP_TYPE_RECTS;
@@ -2171,7 +2171,7 @@ static void marshall_upgrade(DisplayChannelClient *dcc, SpiceMarshaller *m,
     spice_assert(channel && item && item->drawable);
     dcc->init_send_data(SPICE_MSG_DISPLAY_DRAW_COPY);
 
-    red_drawable = item->drawable->red_drawable;
+    red_drawable = item->drawable->red_drawable.get();
     spice_assert(red_drawable->type == QXL_DRAW_COPY);
     spice_assert(red_drawable->u.copy.rop_descriptor == SPICE_ROPD_OP_PUT);
     spice_assert(red_drawable->u.copy.mask.bitmap == nullptr);
diff --git a/server/dcc.cpp b/server/dcc.cpp
index ef98af3b..74e4a821 100644
--- a/server/dcc.cpp
+++ b/server/dcc.cpp
@@ -665,7 +665,7 @@ int dcc_compress_image(DisplayChannelClient *dcc,
         break;
     case SPICE_IMAGE_COMPRESSION_GLZ:
         success = image_encoders_compress_glz(&dcc->priv->encoders, dest, src,
-                                              drawable->red_drawable, &drawable->glz_retention,
+                                              drawable->red_drawable.get(), &drawable->glz_retention,
                                               o_comp_data,
                                               display_channel->priv->enable_zlib_glz_wrap);
         if (success) {
diff --git a/server/display-channel.cpp b/server/display-channel.cpp
index 00f2e861..5093ae03 100644
--- a/server/display-channel.cpp
+++ b/server/display-channel.cpp
@@ -799,7 +799,7 @@ static bool current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawabl
     ++display->priv->add_with_shadow_count;
 #endif
 
-    RedDrawable *red_drawable = item->red_drawable;
+    RedDrawable *red_drawable = item->red_drawable.get();
     SpicePoint delta = {
         .x = red_drawable->u.copy_bits.src_pos.x - red_drawable->bbox.left,
         .y = red_drawable->u.copy_bits.src_pos.y - red_drawable->bbox.top
@@ -1043,7 +1043,7 @@ static bool current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
 
 static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
 {
-    RedDrawable *red_drawable = drawable->red_drawable;
+    RedDrawable *red_drawable = drawable->red_drawable.get();
     SpiceImage *image;
 
     if (display->priv->stream_video == SPICE_STREAM_VIDEO_OFF) {
@@ -1131,7 +1131,7 @@ static void surface_read_bits(DisplayChannel *display, int surface_id,
 
 static void handle_self_bitmap(DisplayChannel *display, Drawable *drawable)
 {
-    RedDrawable *red_drawable = drawable->red_drawable;
+    RedDrawable *red_drawable = drawable->red_drawable.get();
     SpiceImage *image;
     int32_t width;
     int32_t height;
@@ -1274,7 +1274,7 @@ static bool validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawabl
  * @return initialized Drawable or NULL on failure
  */
 static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t effect,
-                                              RedDrawable *red_drawable,
+                                              red::shared_ptr<RedDrawable> &&red_drawable,
                                               uint32_t process_commands_generation)
 {
     Drawable *drawable;
@@ -1282,7 +1282,7 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
     /* Validate all surface ids before updating counters
      * to avoid invalid updates if we find an invalid id.
      */
-    if (!validate_drawable_bbox(display, red_drawable)) {
+    if (!validate_drawable_bbox(display, red_drawable.get())) {
         return nullptr;
     }
     for (const auto surface_id : red_drawable->surface_deps) {
@@ -1297,12 +1297,14 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
     }
 
     drawable->tree_item.effect = effect;
-    drawable->red_drawable = red_drawable_ref(red_drawable);
 
     drawable->surface_id = red_drawable->surface_id;
     display->priv->surfaces[drawable->surface_id].refs++;
 
     memcpy(drawable->surface_deps, red_drawable->surface_deps, sizeof(drawable->surface_deps));
+
+    drawable->red_drawable = red_drawable;
+
     /*
         surface->refs is affected by a drawable (that is
         dependent on the surface) as long as the drawable is alive.
@@ -1321,7 +1323,7 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
 static void display_channel_add_drawable(DisplayChannel *display, Drawable *drawable)
 {
     int surface_id = drawable->surface_id;
-    RedDrawable *red_drawable = drawable->red_drawable;
+    RedDrawable *red_drawable = drawable->red_drawable.get();
 
     red_drawable->mm_time = reds_get_mm_time();
 
@@ -1368,11 +1370,12 @@ static void display_channel_add_drawable(DisplayChannel *display, Drawable *draw
 #endif
 }
 
-void display_channel_process_draw(DisplayChannel *display, RedDrawable *red_drawable,
+void display_channel_process_draw(DisplayChannel *display,
+                                  red::shared_ptr<RedDrawable> &&red_drawable,
                                   uint32_t process_commands_generation)
 {
     Drawable *drawable =
-        display_channel_get_drawable(display, red_drawable->effect, red_drawable,
+        display_channel_get_drawable(display, red_drawable->effect, std::move(red_drawable),
                                      process_commands_generation);
 
     if (!drawable) {
@@ -1630,9 +1633,6 @@ void drawable_unref(Drawable *drawable)
 
     glz_retention_detach_drawables(&drawable->glz_retention);
 
-    if (drawable->red_drawable) {
-        red_drawable_unref(drawable->red_drawable);
-    }
     drawable_free(display, drawable);
 }
 
diff --git a/server/display-channel.h b/server/display-channel.h
index eb25407c..86784131 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -64,7 +64,7 @@ struct Drawable {
     RingItem list_link;
     DrawItem tree_item;
     GList *pipes;
-    RedDrawable *red_drawable;
+    red::shared_ptr<RedDrawable> red_drawable;
 
     GlzImageRetention glz_retention;
 
@@ -121,14 +121,14 @@ void                       display_channel_free_glz_drawables        (DisplayCha
 void                       display_channel_destroy_surface_wait      (DisplayChannel *display,
                                                                       uint32_t surface_id);
 void                       display_channel_destroy_surfaces          (DisplayChannel *display);
-void                       display_channel_process_draw              (DisplayChannel *display,
-                                                                      RedDrawable *red_drawable,
-                                                                      uint32_t process_commands_generation);
 void                       display_channel_gl_scanout                (DisplayChannel *display);
 void                       display_channel_gl_draw                   (DisplayChannel *display,
                                                                       SpiceMsgDisplayGlDraw *draw);
 void                       display_channel_gl_draw_done              (DisplayChannel *display);
 
+void display_channel_process_draw(DisplayChannel *display,
+                                  red::shared_ptr<RedDrawable> &&red_drawable,
+                                  uint32_t process_commands_generation);
 void display_channel_process_surface_cmd(DisplayChannel *display,
                                          red::shared_ptr<const RedSurfaceCmd> &&surface_cmd,
                                          bool loadvm);
diff --git a/server/image-encoders.cpp b/server/image-encoders.cpp
index bb70fa63..4ebcb753 100644
--- a/server/image-encoders.cpp
+++ b/server/image-encoders.cpp
@@ -67,7 +67,7 @@ struct GlzDrawableInstanceItem {
 struct RedGlzDrawable {
     RingItem link;    // ordered by the time it was encoded
     RingItem drawable_link;
-    RedDrawable *red_drawable;
+    red::shared_ptr<RedDrawable> red_drawable;
     GlzDrawableInstanceItem instances_pool[MAX_GLZ_DRAWABLE_INSTANCES];
     Ring instances;
     uint8_t instances_count;
@@ -524,7 +524,7 @@ static void glz_drawable_instance_item_free(GlzDrawableInstanceItem *instance)
         if (glz_drawable->has_drawable) {
             ring_remove(&glz_drawable->drawable_link);
         }
-        red_drawable_unref(glz_drawable->red_drawable);
+        glz_drawable->red_drawable.reset();
         glz_drawable->encoders->shared_data->glz_drawable_count--;
         if (ring_item_is_linked(&glz_drawable->link)) {
             ring_remove(&glz_drawable->link);
@@ -1166,10 +1166,10 @@ static RedGlzDrawable *get_glz_drawable(ImageEncoders *enc, RedDrawable *red_dra
         }
     }
 
-    ret = g_new(RedGlzDrawable, 1);
+    ret = g_new0(RedGlzDrawable, 1);
 
     ret->encoders = enc;
-    ret->red_drawable = red_drawable_ref(red_drawable);
+    ret->red_drawable.reset(red_drawable);
     ret->has_drawable = TRUE;
     ret->instances_count = 0;
     ring_init(&ret->instances);
diff --git a/server/red-parse-qxl.cpp b/server/red-parse-qxl.cpp
index 6dc877d5..25675e7f 100644
--- a/server/red-parse-qxl.cpp
+++ b/server/red-parse-qxl.cpp
@@ -1193,89 +1193,71 @@ static bool red_get_drawable(QXLInstance *qxl, RedMemSlotInfo *slots, int group_
     return ret;
 }
 
-static void red_put_drawable(RedDrawable *red)
+RedDrawable::~RedDrawable()
 {
-    red_put_clip(&red->clip);
-    if (red->self_bitmap_image) {
-        red_put_image(red->self_bitmap_image);
+    red_put_clip(&clip);
+    if (self_bitmap_image) {
+        red_put_image(self_bitmap_image);
     }
-    switch (red->type) {
+    switch (type) {
     case QXL_DRAW_ALPHA_BLEND:
-        red_put_alpha_blend(&red->u.alpha_blend);
+        red_put_alpha_blend(&u.alpha_blend);
         break;
     case QXL_DRAW_BLACKNESS:
-        red_put_blackness(&red->u.blackness);
+        red_put_blackness(&u.blackness);
         break;
     case QXL_DRAW_BLEND:
-        red_put_blend(&red->u.blend);
+        red_put_blend(&u.blend);
         break;
     case QXL_DRAW_COPY:
-        red_put_copy(&red->u.copy);
+        red_put_copy(&u.copy);
         break;
     case QXL_DRAW_FILL:
-        red_put_fill(&red->u.fill);
+        red_put_fill(&u.fill);
         break;
     case QXL_DRAW_OPAQUE:
-        red_put_opaque(&red->u.opaque);
+        red_put_opaque(&u.opaque);
         break;
     case QXL_DRAW_INVERS:
-        red_put_invers(&red->u.invers);
+        red_put_invers(&u.invers);
         break;
     case QXL_DRAW_ROP3:
-        red_put_rop3(&red->u.rop3);
+        red_put_rop3(&u.rop3);
         break;
     case QXL_DRAW_COMPOSITE:
-        red_put_composite(&red->u.composite);
+        red_put_composite(&u.composite);
         break;
     case QXL_DRAW_STROKE:
-        red_put_stroke(&red->u.stroke);
+        red_put_stroke(&u.stroke);
         break;
     case QXL_DRAW_TEXT:
-        red_put_text_ptr(&red->u.text);
+        red_put_text_ptr(&u.text);
         break;
     case QXL_DRAW_TRANSPARENT:
-        red_put_transparent(&red->u.transparent);
+        red_put_transparent(&u.transparent);
         break;
     case QXL_DRAW_WHITENESS:
-        red_put_whiteness(&red->u.whiteness);
+        red_put_whiteness(&u.whiteness);
         break;
     }
-    if (red->qxl != nullptr) {
-        red_qxl_release_resource(red->qxl, red->release_info_ext);
+    if (qxl != nullptr) {
+        red_qxl_release_resource(qxl, release_info_ext);
     }
 }
 
-RedDrawable *red_drawable_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                              int group_id, QXLPHYSICAL addr,
-                              uint32_t flags)
+red::shared_ptr<RedDrawable>
+red_drawable_new(QXLInstance *qxl, RedMemSlotInfo *slots,
+                 int group_id, QXLPHYSICAL addr, uint32_t flags)
 {
-    auto red = g_new0(RedDrawable, 1);
+    auto red = red::make_shared<RedDrawable>();
 
-    red->refs = 1;
-
-    if (!red_get_drawable(qxl, slots, group_id, red, addr, flags)) {
-       red_drawable_unref(red);
-       return nullptr;
+    if (!red_get_drawable(qxl, slots, group_id, red.get(), addr, flags)) {
+        red.reset();
     }
 
     return red;
 }
 
-RedDrawable *red_drawable_ref(RedDrawable *drawable)
-{
-    drawable->refs++;
-    return drawable;
-}
-
-void red_drawable_unref(RedDrawable *red_drawable)
-{
-    if (--red_drawable->refs) {
-        return;
-    }
-    red_put_drawable(red_drawable);
-    g_free(red_drawable);
-}
-
 static bool red_get_update_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots, int group_id,
                                RedUpdateCmd *red, QXLPHYSICAL addr)
 {
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index 52c5e376..7ed0cbd9 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -27,8 +27,8 @@
 
 #include "push-visibility.h"
 
-typedef struct RedDrawable {
-    int refs;
+struct RedDrawable final: public red::simple_ptr_counted<RedDrawable> {
+    ~RedDrawable();
     QXLInstance *qxl;
     QXLReleaseInfoExt release_info_ext;
     uint32_t surface_id;
@@ -60,7 +60,7 @@ typedef struct RedDrawable {
         SpiceWhiteness whiteness;
         SpiceComposite composite;
     } u;
-} RedDrawable;
+};
 
 struct RedUpdateCmd final: public red::simple_ptr_counted<RedUpdateCmd> {
     ~RedUpdateCmd();
@@ -120,11 +120,9 @@ struct RedCursorCmd final: public red::simple_ptr_counted<RedCursorCmd> {
 
 void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl);
 
-RedDrawable *red_drawable_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                              int group_id, QXLPHYSICAL addr,
-                              uint32_t flags);
-RedDrawable *red_drawable_ref(RedDrawable *drawable);
-void red_drawable_unref(RedDrawable *red_drawable);
+red::shared_ptr<RedDrawable>
+red_drawable_new(QXLInstance *qxl, RedMemSlotInfo *slots,
+                 int group_id, QXLPHYSICAL addr, uint32_t flags);
 
 red::shared_ptr<const RedUpdateCmd>
 red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
diff --git a/server/red-worker.cpp b/server/red-worker.cpp
index 3d91da13..d52f375a 100644
--- a/server/red-worker.cpp
+++ b/server/red-worker.cpp
@@ -191,15 +191,13 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
         worker->display_poll_tries = 0;
         switch (ext_cmd.cmd.type) {
         case QXL_CMD_DRAW: {
-            RedDrawable *red_drawable;
-            red_drawable = red_drawable_new(worker->qxl, &worker->mem_slots,
-                                            ext_cmd.group_id, ext_cmd.cmd.data,
-                                            ext_cmd.flags); // returns with 1 ref
+            auto red_drawable = red_drawable_new(worker->qxl, &worker->mem_slots,
+                                                 ext_cmd.group_id, ext_cmd.cmd.data,
+                                                 ext_cmd.flags); // returns with 1 ref
 
-            if (red_drawable != nullptr) {
-                display_channel_process_draw(worker->display_channel, red_drawable,
+            if (red_drawable) {
+                display_channel_process_draw(worker->display_channel, std::move(red_drawable),
                                              worker->process_display_generation);
-                red_drawable_unref(red_drawable);
             }
             break;
         }
diff --git a/server/tree.cpp b/server/tree.cpp
index 8567ae13..b95ae602 100644
--- a/server/tree.cpp
+++ b/server/tree.cpp
@@ -136,7 +136,7 @@ static void dump_item(TreeItem *item, void *data)
             printf("  ");
         }
         printf(item_prefix, 0);
-        show_red_drawable(drawable->red_drawable, nullptr);
+        show_red_drawable(drawable->red_drawable.get(), nullptr);
         for (i = 0; i < di->level; i++) {
             printf("  ");
         }
diff --git a/server/video-stream.cpp b/server/video-stream.cpp
index 162bb25d..9281d5f4 100644
--- a/server/video-stream.cpp
+++ b/server/video-stream.cpp
@@ -224,7 +224,7 @@ static bool is_next_stream_frame(const Drawable *candidate,
         return FALSE;
     }
 
-    red_drawable = candidate->red_drawable;
+    red_drawable = candidate->red_drawable.get();
     if (!container_candidate_allowed) {
         SpiceRect* candidate_src;
 
@@ -692,13 +692,13 @@ static void update_client_playback_delay(void *opaque, uint32_t delay_ms)
 static void bitmap_ref(gpointer data)
 {
     auto red_drawable = (RedDrawable*)data;
-    red_drawable_ref(red_drawable);
+    shared_ptr_add_ref(red_drawable);
 }
 
 static void bitmap_unref(gpointer data)
 {
     auto red_drawable = (RedDrawable*)data;
-    red_drawable_unref(red_drawable);
+    shared_ptr_unref(red_drawable);
 }
 
 /* A helper for dcc_create_stream(). */
commit 110b97e51e02ace4a17e95ae4236deed42acba2d
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 17:03:58 2020 +0100

    red-parse-qxl: Use a base reference class for RedUpdateCmd
    
    Don't code manually reference counting for this structure
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-parse-qxl.cpp b/server/red-parse-qxl.cpp
index 419da12b..6dc877d5 100644
--- a/server/red-parse-qxl.cpp
+++ b/server/red-parse-qxl.cpp
@@ -1295,45 +1295,26 @@ static bool red_get_update_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
     return true;
 }
 
-static void red_put_update_cmd(RedUpdateCmd *red)
+RedUpdateCmd::~RedUpdateCmd()
 {
-    if (red->qxl != nullptr) {
-        red_qxl_release_resource(red->qxl, red->release_info_ext);
+    if (qxl != nullptr) {
+        red_qxl_release_resource(qxl, release_info_ext);
     }
 }
 
-RedUpdateCmd *red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                                 int group_id, QXLPHYSICAL addr)
+red::shared_ptr<const RedUpdateCmd>
+red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
+                   int group_id, QXLPHYSICAL addr)
 {
-    RedUpdateCmd *red;
-
-    red = g_new0(RedUpdateCmd, 1);
+    auto red = red::make_shared<RedUpdateCmd>();
 
-    red->refs = 1;
-
-    if (!red_get_update_cmd(qxl, slots, group_id, red, addr)) {
-        red_update_cmd_unref(red);
-        return nullptr;
+    if (!red_get_update_cmd(qxl, slots, group_id, red.get(), addr)) {
+        red.reset();
     }
 
     return red;
 }
 
-RedUpdateCmd *red_update_cmd_ref(RedUpdateCmd *red)
-{
-    red->refs++;
-    return red;
-}
-
-void red_update_cmd_unref(RedUpdateCmd *red)
-{
-    if (--red->refs) {
-        return;
-    }
-    red_put_update_cmd(red);
-    g_free(red);
-}
-
 static bool red_get_message(QXLInstance *qxl_instance, RedMemSlotInfo *slots, int group_id,
                             RedMessage *red, QXLPHYSICAL addr)
 {
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index 0226659a..52c5e376 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -62,14 +62,14 @@ typedef struct RedDrawable {
     } u;
 } RedDrawable;
 
-typedef struct RedUpdateCmd {
+struct RedUpdateCmd final: public red::simple_ptr_counted<RedUpdateCmd> {
+    ~RedUpdateCmd();
     QXLInstance *qxl;
     QXLReleaseInfoExt release_info_ext;
-    int refs;
     SpiceRect area;
     uint32_t update_id;
     uint32_t surface_id;
-} RedUpdateCmd;
+};
 
 struct RedMessage final: public red::simple_ptr_counted<RedMessage> {
     ~RedMessage();
@@ -126,10 +126,9 @@ RedDrawable *red_drawable_new(QXLInstance *qxl, RedMemSlotInfo *slots,
 RedDrawable *red_drawable_ref(RedDrawable *drawable);
 void red_drawable_unref(RedDrawable *red_drawable);
 
-RedUpdateCmd *red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                                 int group_id, QXLPHYSICAL addr);
-RedUpdateCmd *red_update_cmd_ref(RedUpdateCmd *red);
-void red_update_cmd_unref(RedUpdateCmd *red);
+red::shared_ptr<const RedUpdateCmd>
+red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
+                   int group_id, QXLPHYSICAL addr);
 
 red::shared_ptr<const RedMessage>
 red_message_new(QXLInstance *qxl, RedMemSlotInfo *slots,
diff --git a/server/red-worker.cpp b/server/red-worker.cpp
index 6e2eeb6d..3d91da13 100644
--- a/server/red-worker.cpp
+++ b/server/red-worker.cpp
@@ -204,11 +204,9 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
             break;
         }
         case QXL_CMD_UPDATE: {
-            RedUpdateCmd *update;
-
-            update = red_update_cmd_new(worker->qxl, &worker->mem_slots,
-                                        ext_cmd.group_id, ext_cmd.cmd.data);
-            if (update == nullptr) {
+            auto update = red_update_cmd_new(worker->qxl, &worker->mem_slots,
+                                             ext_cmd.group_id, ext_cmd.cmd.data);
+            if (!update) {
                 break;
             }
             if (!display_channel_validate_surface(worker->display_channel, update->surface_id)) {
@@ -217,7 +215,6 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
                 display_channel_draw(worker->display_channel, &update->area, update->surface_id);
                 red_qxl_notify_update(worker->qxl, update->update_id);
             }
-            red_update_cmd_unref(update);
             break;
         }
         case QXL_CMD_MESSAGE: {
commit 45f2d94ac36c67ec6a610ae2b043631de0d7d37e
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 16:59:52 2020 +0100

    red-parse-qxl: Use a base reference class for RedMessage
    
    Don't code manually reference counting for this structure
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-parse-qxl.cpp b/server/red-parse-qxl.cpp
index 66f6b5d7..419da12b 100644
--- a/server/red-parse-qxl.cpp
+++ b/server/red-parse-qxl.cpp
@@ -1367,45 +1367,26 @@ static bool red_get_message(QXLInstance *qxl_instance, RedMemSlotInfo *slots, in
     return true;
 }
 
-static void red_put_message(RedMessage *red)
+RedMessage::~RedMessage()
 {
-    if (red->qxl != nullptr) {
-        red_qxl_release_resource(red->qxl, red->release_info_ext);
+    if (qxl != nullptr) {
+        red_qxl_release_resource(qxl, release_info_ext);
     }
 }
 
-RedMessage *red_message_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                            int group_id, QXLPHYSICAL addr)
+red::shared_ptr<const RedMessage>
+red_message_new(QXLInstance *qxl, RedMemSlotInfo *slots,
+                int group_id, QXLPHYSICAL addr)
 {
-    RedMessage *red;
-
-    red = g_new0(RedMessage, 1);
-
-    red->refs = 1;
+    auto red = red::make_shared<RedMessage>();
 
-    if (!red_get_message(qxl, slots, group_id, red, addr)) {
-        red_message_unref(red);
-        return nullptr;
+    if (!red_get_message(qxl, slots, group_id, red.get(), addr)) {
+        red.reset();
     }
 
     return red;
 }
 
-RedMessage *red_message_ref(RedMessage *red)
-{
-    red->refs++;
-    return red;
-}
-
-void red_message_unref(RedMessage *red)
-{
-    if (--red->refs) {
-        return;
-    }
-    red_put_message(red);
-    g_free(red);
-}
-
 static unsigned int surface_format_to_bpp(uint32_t format)
 {
     switch (format) {
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index 1eb0d928..0226659a 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -71,13 +71,13 @@ typedef struct RedUpdateCmd {
     uint32_t surface_id;
 } RedUpdateCmd;
 
-typedef struct RedMessage {
+struct RedMessage final: public red::simple_ptr_counted<RedMessage> {
+    ~RedMessage();
     QXLInstance *qxl;
     QXLReleaseInfoExt release_info_ext;
-    int refs;
     int len;
     uint8_t *data;
-} RedMessage;
+};
 
 typedef struct RedSurfaceCreate {
     uint32_t format;
@@ -131,10 +131,9 @@ RedUpdateCmd *red_update_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
 RedUpdateCmd *red_update_cmd_ref(RedUpdateCmd *red);
 void red_update_cmd_unref(RedUpdateCmd *red);
 
-RedMessage *red_message_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                            int group_id, QXLPHYSICAL addr);
-RedMessage *red_message_ref(RedMessage *red);
-void red_message_unref(RedMessage *red);
+red::shared_ptr<const RedMessage>
+red_message_new(QXLInstance *qxl, RedMemSlotInfo *slots,
+                int group_id, QXLPHYSICAL addr);
 
 bool red_validate_surface(uint32_t width, uint32_t height,
                           int32_t stride, uint32_t format);
diff --git a/server/red-worker.cpp b/server/red-worker.cpp
index 62028a53..6e2eeb6d 100644
--- a/server/red-worker.cpp
+++ b/server/red-worker.cpp
@@ -221,17 +221,14 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
             break;
         }
         case QXL_CMD_MESSAGE: {
-            RedMessage *message;
-
-            message = red_message_new(worker->qxl, &worker->mem_slots,
-                                      ext_cmd.group_id, ext_cmd.cmd.data);
-            if (message == nullptr) {
+            auto message = red_message_new(worker->qxl, &worker->mem_slots,
+                                           ext_cmd.group_id, ext_cmd.cmd.data);
+            if (!message) {
                 break;
             }
 #ifdef DEBUG
             spice_warning("MESSAGE: %.*s", message->len, message->data);
 #endif
-            red_message_unref(message);
             break;
         }
         case QXL_CMD_SURFACE:
commit 6eac8cc08f30cd769849f0a0c71702c1bb93b6b8
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 16:34:39 2020 +0100

    red-parse-qxl: Use a base reference class for RedSurfaceCmd
    
    Don't code manually reference counting for this structure
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/display-channel-private.h b/server/display-channel-private.h
index 03077de1..49026663 100644
--- a/server/display-channel-private.h
+++ b/server/display-channel-private.h
@@ -54,10 +54,10 @@ typedef struct RedSurface {
     //fix me - better handling here
     /* 'create_cmd' holds surface data through a pointer to guest memory, it
      * must be valid as long as the surface is valid */
-    RedSurfaceCmd *create_cmd;
+    red::shared_ptr<const RedSurfaceCmd> create_cmd;
     /* QEMU expects the guest data for the command to be valid as long as the
      * surface is valid */
-    RedSurfaceCmd *destroy_cmd;
+    red::shared_ptr<const RedSurfaceCmd> destroy_cmd;
 } RedSurface;
 
 typedef struct MonitorsConfig {
diff --git a/server/display-channel.cpp b/server/display-channel.cpp
index 52abe18f..00f2e861 100644
--- a/server/display-channel.cpp
+++ b/server/display-channel.cpp
@@ -241,14 +241,8 @@ void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
     spice_assert(surface->context.canvas);
 
     surface->context.canvas->ops->destroy(surface->context.canvas);
-    if (surface->create_cmd != nullptr) {
-        red_surface_cmd_unref(surface->create_cmd);
-        surface->create_cmd = nullptr;
-    }
-    if (surface->destroy_cmd != nullptr) {
-        red_surface_cmd_unref(surface->destroy_cmd);
-        surface->destroy_cmd = nullptr;
-    }
+    surface->create_cmd.reset();
+    surface->destroy_cmd.reset();
 
     region_destroy(&surface->draw_dirty_region);
     surface->context.canvas = nullptr;
@@ -2098,8 +2092,8 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
         }
         memset(data, 0, height*abs(stride));
     }
-    g_warn_if_fail(surface->create_cmd == nullptr);
-    g_warn_if_fail(surface->destroy_cmd == nullptr);
+    g_warn_if_fail(!surface->create_cmd);
+    g_warn_if_fail(!surface->destroy_cmd);
     ring_init(&surface->current);
     ring_init(&surface->current_list);
     ring_init(&surface->depend_on_me);
@@ -2230,8 +2224,8 @@ DisplayChannel::DisplayChannel(RedsState *reds,
 }
 
 void display_channel_process_surface_cmd(DisplayChannel *display,
-                                         RedSurfaceCmd *surface_cmd,
-                                         int loadvm)
+                                         red::shared_ptr<const RedSurfaceCmd> &&surface_cmd,
+                                         bool loadvm)
 {
     uint32_t surface_id;
     RedSurface *surface;
@@ -2266,7 +2260,7 @@ void display_channel_process_surface_cmd(DisplayChannel *display,
                                        reloaded_surface,
                                        // reloaded surfaces will be sent on demand
                                        !reloaded_surface);
-        surface->create_cmd = red_surface_cmd_ref(surface_cmd);
+        surface->create_cmd = surface_cmd;
         break;
     }
     case QXL_SURFACE_CMD_DESTROY:
@@ -2274,7 +2268,7 @@ void display_channel_process_surface_cmd(DisplayChannel *display,
             spice_warning("avoiding destroying a surface twice");
             break;
         }
-        surface->destroy_cmd = red_surface_cmd_ref(surface_cmd);
+        surface->destroy_cmd = surface_cmd;
         display_channel_destroy_surface(display, surface_id);
         break;
     default:
diff --git a/server/display-channel.h b/server/display-channel.h
index da8ae07f..eb25407c 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -124,14 +124,14 @@ void                       display_channel_destroy_surfaces          (DisplayCha
 void                       display_channel_process_draw              (DisplayChannel *display,
                                                                       RedDrawable *red_drawable,
                                                                       uint32_t process_commands_generation);
-void                       display_channel_process_surface_cmd       (DisplayChannel *display,
-                                                                      RedSurfaceCmd *surface_cmd,
-                                                                      int loadvm);
 void                       display_channel_gl_scanout                (DisplayChannel *display);
 void                       display_channel_gl_draw                   (DisplayChannel *display,
                                                                       SpiceMsgDisplayGlDraw *draw);
 void                       display_channel_gl_draw_done              (DisplayChannel *display);
 
+void display_channel_process_surface_cmd(DisplayChannel *display,
+                                         red::shared_ptr<const RedSurfaceCmd> &&surface_cmd,
+                                         bool loadvm);
 void display_channel_update_monitors_config(DisplayChannel *display, const QXLMonitorsConfig *config,
                                             uint16_t count, uint16_t max_allowed);
 void display_channel_set_monitors_config_to_primary(DisplayChannel *display);
diff --git a/server/red-parse-qxl.cpp b/server/red-parse-qxl.cpp
index 198179a3..66f6b5d7 100644
--- a/server/red-parse-qxl.cpp
+++ b/server/red-parse-qxl.cpp
@@ -1490,45 +1490,26 @@ static bool red_get_surface_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots
     return true;
 }
 
-static void red_put_surface_cmd(RedSurfaceCmd *red)
+RedSurfaceCmd::~RedSurfaceCmd()
 {
-    if (red->qxl) {
-        red_qxl_release_resource(red->qxl, red->release_info_ext);
+    if (qxl) {
+        red_qxl_release_resource(qxl, release_info_ext);
     }
 }
 
-RedSurfaceCmd *red_surface_cmd_new(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
-                                   int group_id, QXLPHYSICAL addr)
+red::shared_ptr<const RedSurfaceCmd>
+red_surface_cmd_new(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
+                    int group_id, QXLPHYSICAL addr)
 {
-    RedSurfaceCmd *cmd;
-
-    cmd = g_new0(RedSurfaceCmd, 1);
+    auto cmd = red::make_shared<RedSurfaceCmd>();
 
-    cmd->refs = 1;
-
-    if (!red_get_surface_cmd(qxl_instance, slots, group_id, cmd, addr)) {
-        red_surface_cmd_unref(cmd);
-        return nullptr;
+    if (!red_get_surface_cmd(qxl_instance, slots, group_id, cmd.get(), addr)) {
+        cmd.reset();
     }
 
     return cmd;
 }
 
-RedSurfaceCmd *red_surface_cmd_ref(RedSurfaceCmd *cmd)
-{
-    cmd->refs++;
-    return cmd;
-}
-
-void red_surface_cmd_unref(RedSurfaceCmd *cmd)
-{
-    if (--cmd->refs) {
-        return;
-    }
-    red_put_surface_cmd(cmd);
-    g_free(cmd);
-}
-
 static bool red_get_cursor(RedMemSlotInfo *slots, int group_id,
                            SpiceCursor *red, QXLPHYSICAL addr)
 {
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index d1aab512..1eb0d928 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -87,17 +87,17 @@ typedef struct RedSurfaceCreate {
     uint8_t *data;
 } RedSurfaceCreate;
 
-typedef struct RedSurfaceCmd {
+struct RedSurfaceCmd final: public red::simple_ptr_counted<RedSurfaceCmd> {
+    ~RedSurfaceCmd();
     QXLInstance *qxl;
     QXLReleaseInfoExt release_info_ext;
-    int refs;
     uint32_t surface_id;
     uint8_t type;
     uint32_t flags;
     union {
         RedSurfaceCreate surface_create;
     } u;
-} RedSurfaceCmd;
+};
 
 struct RedCursorCmd final: public red::simple_ptr_counted<RedCursorCmd> {
     ~RedCursorCmd();
@@ -139,10 +139,9 @@ void red_message_unref(RedMessage *red);
 bool red_validate_surface(uint32_t width, uint32_t height,
                           int32_t stride, uint32_t format);
 
-RedSurfaceCmd *red_surface_cmd_new(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
-                                   int group_id, QXLPHYSICAL addr);
-RedSurfaceCmd *red_surface_cmd_ref(RedSurfaceCmd *cmd);
-void red_surface_cmd_unref(RedSurfaceCmd *cmd);
+red::shared_ptr<const RedSurfaceCmd>
+red_surface_cmd_new(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
+                    int group_id, QXLPHYSICAL addr);
 
 red::shared_ptr<const RedCursorCmd>
 red_cursor_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots, int group_id, QXLPHYSICAL addr);
diff --git a/server/red-worker.cpp b/server/red-worker.cpp
index 9aad023b..62028a53 100644
--- a/server/red-worker.cpp
+++ b/server/red-worker.cpp
@@ -145,15 +145,12 @@ static int red_process_cursor(RedWorker *worker, int *ring_is_empty)
 
 static gboolean red_process_surface_cmd(RedWorker *worker, QXLCommandExt *ext, gboolean loadvm)
 {
-    RedSurfaceCmd *surface_cmd;
-
-    surface_cmd = red_surface_cmd_new(worker->qxl, &worker->mem_slots,
-                                      ext->group_id, ext->cmd.data);
-    if (surface_cmd == nullptr) {
+    auto surface_cmd = red_surface_cmd_new(worker->qxl, &worker->mem_slots,
+                                           ext->group_id, ext->cmd.data);
+    if (!surface_cmd) {
         return false;
     }
-    display_channel_process_surface_cmd(worker->display_channel, surface_cmd, loadvm);
-    red_surface_cmd_unref(surface_cmd);
+    display_channel_process_surface_cmd(worker->display_channel, std::move(surface_cmd), loadvm);
 
     return true;
 }
diff --git a/server/tests/test-qxl-parsing.cpp b/server/tests/test-qxl-parsing.cpp
index 510e275b..d68879f1 100644
--- a/server/tests/test-qxl-parsing.cpp
+++ b/server/tests/test-qxl-parsing.cpp
@@ -111,16 +111,15 @@ static void test_memslot_invalid_addresses(void)
 static void test_no_issues(void)
 {
     RedMemSlotInfo mem_info;
-    RedSurfaceCmd *cmd;
     QXLSurfaceCmd qxl;
 
     init_meminfo(&mem_info);
     init_qxl_surface(&qxl);
 
     /* try to create a surface with no issues, should succeed */
-    cmd = red_surface_cmd_new(NULL, &mem_info, 0, to_physical(&qxl));
-    g_assert_nonnull(cmd);
-    red_surface_cmd_unref(cmd);
+    auto cmd = red_surface_cmd_new(NULL, &mem_info, 0, to_physical(&qxl));
+    g_assert(cmd);
+    cmd.reset();
 
     deinit_qxl_surface(&qxl);
     memslot_info_destroy(&mem_info);
@@ -129,7 +128,6 @@ static void test_no_issues(void)
 static void test_stride_too_small(void)
 {
     RedMemSlotInfo mem_info;
-    RedSurfaceCmd *cmd;
     QXLSurfaceCmd qxl;
 
     init_meminfo(&mem_info);
@@ -140,8 +138,8 @@ static void test_stride_too_small(void)
      * This can be used to cause buffer overflows so refuse it.
      */
     qxl.u.surface_create.stride = 256;
-    cmd = red_surface_cmd_new(NULL, &mem_info, 0, to_physical(&qxl));
-    g_assert_null(cmd);
+    auto cmd = red_surface_cmd_new(NULL, &mem_info, 0, to_physical(&qxl));
+    g_assert(!cmd);
 
     deinit_qxl_surface(&qxl);
     memslot_info_destroy(&mem_info);
@@ -150,7 +148,6 @@ static void test_stride_too_small(void)
 static void test_too_big_image(void)
 {
     RedMemSlotInfo mem_info;
-    RedSurfaceCmd *cmd;
     QXLSurfaceCmd qxl;
 
     init_meminfo(&mem_info);
@@ -166,8 +163,8 @@ static void test_too_big_image(void)
     qxl.u.surface_create.stride = 0x08000004 * 4;
     qxl.u.surface_create.width = 0x08000004;
     qxl.u.surface_create.height = 0x40000020;
-    cmd = red_surface_cmd_new(NULL, &mem_info, 0, to_physical(&qxl));
-    g_assert_null(cmd);
+    auto cmd = red_surface_cmd_new(NULL, &mem_info, 0, to_physical(&qxl));
+    g_assert(!cmd);
 
     deinit_qxl_surface(&qxl);
     memslot_info_destroy(&mem_info);
commit 1d4fb2fee7a0703ceba67c27d5d8f657caf339a0
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue May 5 15:42:47 2020 +0100

    red-parse-qxl: Use a base reference class for RedCursorCmd
    
    Don't code manually reference counting for this structure
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/Makefile.am b/server/Makefile.am
index 2c7479d9..5260051b 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -157,7 +157,7 @@ libserver_la_SOURCES =				\
 	red-pipe-item.h				\
 	red-qxl.cpp				\
 	red-qxl.h				\
-	red-record-qxl.c			\
+	red-record-qxl.cpp			\
 	red-record-qxl.h			\
 	red-replay-qxl.cpp			\
 	reds.cpp				\
diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp
index 8bb06134..beb004ea 100644
--- a/server/cursor-channel.cpp
+++ b/server/cursor-channel.cpp
@@ -26,37 +26,24 @@
 #include "reds.h"
 
 struct RedCursorPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_CURSOR> {
-    explicit RedCursorPipeItem(RedCursorCmd *cmd);
-    ~RedCursorPipeItem() override;
-    RedCursorCmd *red_cursor;
+    explicit RedCursorPipeItem(const red::shared_ptr<const RedCursorCmd>& cmd);
+    red::shared_ptr<const RedCursorCmd> red_cursor;
 };
 
-RedCursorPipeItem::RedCursorPipeItem(RedCursorCmd *cmd):
-    red_cursor(red_cursor_cmd_ref(cmd))
+RedCursorPipeItem::RedCursorPipeItem(const red::shared_ptr<const RedCursorCmd>& cmd):
+    red_cursor(cmd)
 {
 }
 
-RedCursorPipeItem::~RedCursorPipeItem()
-{
-    red_cursor_cmd_unref(red_cursor);
-}
-
-static void cursor_channel_set_item(CursorChannel *cursor, RedCursorPipeItem *item)
-{
-    cursor->item.reset(item);
-}
-
 static void cursor_fill(CursorChannelClient *ccc, RedCursorPipeItem *cursor,
                         SpiceCursor *red_cursor, SpiceMarshaller *m)
 {
-    RedCursorCmd *cursor_cmd;
-
     if (!cursor) {
         red_cursor->flags = SPICE_CURSOR_FLAGS_NONE;
         return;
     }
 
-    cursor_cmd = cursor->red_cursor;
+    auto cursor_cmd = cursor->red_cursor.get();
     *red_cursor = cursor_cmd->u.set.shape;
 
     if (red_cursor->header.unique) {
@@ -100,11 +87,10 @@ static void red_marshall_cursor(CursorChannelClient *ccc,
 {
     CursorChannel *cursor_channel = ccc->get_channel();
     RedCursorPipeItem *item = cursor_pipe_item;
-    RedCursorCmd *cmd;
 
     spice_return_if_fail(cursor_channel);
 
-    cmd = item->red_cursor;
+    auto cmd = item->red_cursor.get();
     switch (cmd->type) {
     case QXL_CURSOR_MOVE:
         {
@@ -189,7 +175,7 @@ cursor_channel_new(RedsState *server, int id,
     return red::make_shared<CursorChannel>(server, id, core, dispatcher);
 }
 
-void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
+void CursorChannel::process_cmd(red::shared_ptr<const RedCursorCmd> &&cursor_cmd)
 {
     bool cursor_show = false;
 
@@ -200,7 +186,7 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
     switch (cursor_cmd->type) {
     case QXL_CURSOR_SET:
         cursor_visible = !!cursor_cmd->u.set.visible;
-        cursor_channel_set_item(this, cursor_pipe_item.get());
+        item = cursor_pipe_item;
         break;
     case QXL_CURSOR_MOVE:
         cursor_show = !cursor_visible;
@@ -229,7 +215,7 @@ void CursorChannel::process_cmd(RedCursorCmd *cursor_cmd)
 
 void CursorChannel::reset()
 {
-    cursor_channel_set_item(this, nullptr);
+    item.reset();
     cursor_visible = true;
     cursor_position.x = cursor_position.y = 0;
     cursor_trail_length = cursor_trail_frequency = 0;
diff --git a/server/cursor-channel.h b/server/cursor-channel.h
index f0f59436..0461a942 100644
--- a/server/cursor-channel.h
+++ b/server/cursor-channel.h
@@ -38,7 +38,7 @@ struct CursorChannel final: public CommonGraphicsChannel
     ~CursorChannel();
     void reset();
     void do_init();
-    void process_cmd(RedCursorCmd *cursor_cmd);
+    void process_cmd(red::shared_ptr<const RedCursorCmd> &&cursor_cmd);
     void set_mouse_mode(uint32_t mode);
     void on_connect(RedClient *client, RedStream *stream, int migration,
                     RedChannelCapabilities *caps) override;
diff --git a/server/meson.build b/server/meson.build
index fe8d5d63..a8da777f 100644
--- a/server/meson.build
+++ b/server/meson.build
@@ -136,7 +136,7 @@ spice_server_sources = [
   'red-pipe-item.h',
   'red-qxl.cpp',
   'red-qxl.h',
-  'red-record-qxl.c',
+  'red-record-qxl.cpp',
   'red-record-qxl.h',
   'red-replay-qxl.cpp',
   'reds.cpp',
diff --git a/server/red-parse-qxl.cpp b/server/red-parse-qxl.cpp
index ec4b17e6..198179a3 100644
--- a/server/red-parse-qxl.cpp
+++ b/server/red-parse-qxl.cpp
@@ -1609,46 +1609,26 @@ static bool red_get_cursor_cmd(QXLInstance *qxl_instance, RedMemSlotInfo *slots,
     return true;
 }
 
-RedCursorCmd *red_cursor_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                                 int group_id, QXLPHYSICAL addr)
+red::shared_ptr<const RedCursorCmd>
+red_cursor_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots, int group_id, QXLPHYSICAL addr)
 {
-    RedCursorCmd *cmd;
-
-    cmd = g_new0(RedCursorCmd, 1);
+    auto cmd = red::make_shared<RedCursorCmd>();
 
-    cmd->refs = 1;
-
-    if (!red_get_cursor_cmd(qxl, slots, group_id, cmd, addr)) {
-        red_cursor_cmd_unref(cmd);
-        return nullptr;
+    if (!red_get_cursor_cmd(qxl, slots, group_id, cmd.get(), addr)) {
+        cmd.reset();
     }
 
     return cmd;
 }
 
-static void red_put_cursor_cmd(RedCursorCmd *red)
+RedCursorCmd::~RedCursorCmd()
 {
-    switch (red->type) {
+    switch (type) {
     case QXL_CURSOR_SET:
-        red_put_cursor(&red->u.set.shape);
+        red_put_cursor(&u.set.shape);
         break;
     }
-    if (red->qxl) {
-        red_qxl_release_resource(red->qxl, red->release_info_ext);
-    }
-}
-
-RedCursorCmd *red_cursor_cmd_ref(RedCursorCmd *red)
-{
-    red->refs++;
-    return red;
-}
-
-void red_cursor_cmd_unref(RedCursorCmd *red)
-{
-    if (--red->refs) {
-        return;
+    if (qxl) {
+        red_qxl_release_resource(qxl, release_info_ext);
     }
-    red_put_cursor_cmd(red);
-    g_free(red);
 }
diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
index c7206516..d1aab512 100644
--- a/server/red-parse-qxl.h
+++ b/server/red-parse-qxl.h
@@ -23,8 +23,9 @@
 
 #include "red-common.h"
 #include "memslot.h"
+#include "utils.hpp"
 
-SPICE_BEGIN_DECLS
+#include "push-visibility.h"
 
 typedef struct RedDrawable {
     int refs;
@@ -98,10 +99,10 @@ typedef struct RedSurfaceCmd {
     } u;
 } RedSurfaceCmd;
 
-typedef struct RedCursorCmd {
+struct RedCursorCmd final: public red::simple_ptr_counted<RedCursorCmd> {
+    ~RedCursorCmd();
     QXLInstance *qxl;
     QXLReleaseInfoExt release_info_ext;
-    int refs;
     uint8_t type;
     union {
         struct {
@@ -115,7 +116,7 @@ typedef struct RedCursorCmd {
         } trail;
         SpicePoint16 position;
     } u;
-} RedCursorCmd;
+};
 
 void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl);
 
@@ -143,11 +144,9 @@ RedSurfaceCmd *red_surface_cmd_new(QXLInstance *qxl_instance, RedMemSlotInfo *sl
 RedSurfaceCmd *red_surface_cmd_ref(RedSurfaceCmd *cmd);
 void red_surface_cmd_unref(RedSurfaceCmd *cmd);
 
-RedCursorCmd *red_cursor_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots,
-                                 int group_id, QXLPHYSICAL addr);
-RedCursorCmd *red_cursor_cmd_ref(RedCursorCmd *red);
-void red_cursor_cmd_unref(RedCursorCmd *red);
+red::shared_ptr<const RedCursorCmd>
+red_cursor_cmd_new(QXLInstance *qxl, RedMemSlotInfo *slots, int group_id, QXLPHYSICAL addr);
 
-SPICE_END_DECLS
+#include "pop-visibility.h"
 
 #endif /* RED_PARSE_QXL_H_ */
diff --git a/server/red-record-qxl.c b/server/red-record-qxl.cpp
similarity index 100%
rename from server/red-record-qxl.c
rename to server/red-record-qxl.cpp
diff --git a/server/red-stream-device.cpp b/server/red-stream-device.cpp
index 65eb0d61..92ba0d94 100644
--- a/server/red-stream-device.cpp
+++ b/server/red-stream-device.cpp
@@ -378,10 +378,10 @@ get_cursor_type_bits(unsigned int cursor_type)
     }
 }
 
-static RedCursorCmd *
+static red::shared_ptr<const RedCursorCmd>
 stream_msg_cursor_set_to_cursor_cmd(const StreamMsgCursorSet *msg, size_t msg_size)
 {
-    auto cmd = g_new0(RedCursorCmd, 1);
+    auto cmd = red::make_shared<RedCursorCmd>();
     cmd->type = QXL_CURSOR_SET;
     cmd->u.set.position.x = 0; // TODO
     cmd->u.set.position.y = 0; // TODO
@@ -397,14 +397,12 @@ stream_msg_cursor_set_to_cursor_cmd(const StreamMsgCursorSet *msg, size_t msg_si
     /* Limit cursor size to prevent DoS */
     if (cursor->header.width > STREAM_MSG_CURSOR_SET_MAX_WIDTH ||
         cursor->header.height > STREAM_MSG_CURSOR_SET_MAX_HEIGHT) {
-        g_free(cmd);
-        return nullptr;
+        return red::shared_ptr<const RedCursorCmd>();
     }
 
     const unsigned int cursor_bits = get_cursor_type_bits(cursor->header.type);
     if (cursor_bits == 0) {
-        g_free(cmd);
-        return nullptr;
+        return red::shared_ptr<const RedCursorCmd>();
     }
 
     /* Check that enough data has been sent for the cursor.
@@ -413,8 +411,7 @@ stream_msg_cursor_set_to_cursor_cmd(const StreamMsgCursorSet *msg, size_t msg_si
     size_t size_required = cursor->header.width * cursor->header.height;
     size_required = SPICE_ALIGN(size_required * cursor_bits, 8) / 8U;
     if (msg_size < sizeof(StreamMsgCursorSet) + size_required) {
-        g_free(cmd);
-        return nullptr;
+        return red::shared_ptr<const RedCursorCmd>();
     }
     cursor->data_size = size_required;
     cursor->data = (uint8_t*) g_memdup2(msg->data, size_required);
@@ -453,11 +450,11 @@ StreamDevice::handle_msg_cursor_set()
     }
 
     // transform the message to a cursor command and process it
-    RedCursorCmd *cmd = stream_msg_cursor_set_to_cursor_cmd(&msg->cursor_set, msg_pos);
+    auto cmd = stream_msg_cursor_set_to_cursor_cmd(&msg->cursor_set, msg_pos);
     if (!cmd) {
         return handle_msg_invalid(nullptr);
     }
-    cursor_channel->process_cmd(cmd);
+    cursor_channel->process_cmd(std::move(cmd));
 
     return true;
 }
@@ -478,12 +475,12 @@ StreamDevice::handle_msg_cursor_move()
     move->x = GINT32_FROM_LE(move->x);
     move->y = GINT32_FROM_LE(move->y);
 
-    auto cmd = g_new0(RedCursorCmd, 1);
+    auto cmd = red::make_shared<RedCursorCmd>();
     cmd->type = QXL_CURSOR_MOVE;
     cmd->u.position.x = move->x;
     cmd->u.position.y = move->y;
 
-    cursor_channel->process_cmd(cmd);
+    cursor_channel->process_cmd(std::move(cmd));
 
     return true;
 }
diff --git a/server/red-worker.cpp b/server/red-worker.cpp
index 2be223b4..9aad023b 100644
--- a/server/red-worker.cpp
+++ b/server/red-worker.cpp
@@ -90,16 +90,13 @@ struct RedWorker {
 
 static gboolean red_process_cursor_cmd(RedWorker *worker, const QXLCommandExt *ext)
 {
-    RedCursorCmd *cursor_cmd;
-
-    cursor_cmd = red_cursor_cmd_new(worker->qxl, &worker->mem_slots,
-                                    ext->group_id, ext->cmd.data);
-    if (cursor_cmd == nullptr) {
+    auto cursor_cmd = red_cursor_cmd_new(worker->qxl, &worker->mem_slots,
+                                         ext->group_id, ext->cmd.data);
+    if (!cursor_cmd) {
         return FALSE;
     }
 
-    worker->cursor_channel->process_cmd(cursor_cmd);
-    red_cursor_cmd_unref(cursor_cmd);
+    worker->cursor_channel->process_cmd(std::move(cursor_cmd));
 
     return TRUE;
 }
diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 19058037..5918cb9d 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -83,6 +83,7 @@ endif
 test_channel_SOURCES = test-channel.cpp
 test_stream_device_SOURCES = test-stream-device.cpp
 test_dispatcher_SOURCES = test-dispatcher.cpp
+test_qxl_parsing_SOURCES = test-qxl-parsing.cpp
 
 if !OS_WIN32
 check_PROGRAMS +=				\
diff --git a/server/tests/meson.build b/server/tests/meson.build
index 4f150a0b..1ae7d37c 100644
--- a/server/tests/meson.build
+++ b/server/tests/meson.build
@@ -44,7 +44,7 @@ tests = [
   ['test-stat', true],
   ['test-agent-msg-filter', true],
   ['test-loop', true],
-  ['test-qxl-parsing', true],
+  ['test-qxl-parsing', true, 'cpp'],
   ['test-leaks', true],
   ['test-vdagent', true],
   ['test-fail-on-null-core-interface', true],
diff --git a/server/tests/test-qxl-parsing.c b/server/tests/test-qxl-parsing.cpp
similarity index 94%
rename from server/tests/test-qxl-parsing.c
rename to server/tests/test-qxl-parsing.cpp
index ee234b61..510e275b 100644
--- a/server/tests/test-qxl-parsing.c
+++ b/server/tests/test-qxl-parsing.cpp
@@ -176,7 +176,6 @@ static void test_too_big_image(void)
 static void test_cursor_command(void)
 {
     RedMemSlotInfo mem_info;
-    RedCursorCmd *red_cursor_cmd;
     QXLCursorCmd cursor_cmd;
     QXLCursor *cursor;
 
@@ -194,9 +193,9 @@ static void test_cursor_command(void)
 
     cursor_cmd.u.set.shape = to_physical(cursor);
 
-    red_cursor_cmd = red_cursor_cmd_new(NULL, &mem_info, 0, to_physical(&cursor_cmd));
-    g_assert_nonnull(red_cursor_cmd);
-    red_cursor_cmd_unref(red_cursor_cmd);
+    auto red_cursor_cmd = red_cursor_cmd_new(NULL, &mem_info, 0, to_physical(&cursor_cmd));
+    g_assert(red_cursor_cmd);
+    red_cursor_cmd.reset();
     g_free(cursor);
     memslot_info_destroy(&mem_info);
 }
@@ -204,7 +203,6 @@ static void test_cursor_command(void)
 static void test_circular_empty_chunks(void)
 {
     RedMemSlotInfo mem_info;
-    RedCursorCmd *red_cursor_cmd;
     QXLCursorCmd cursor_cmd;
     QXLCursor *cursor;
     QXLDataChunk *chunks[2];
@@ -228,14 +226,14 @@ static void test_circular_empty_chunks(void)
 
     cursor_cmd.u.set.shape = to_physical(cursor);
 
-    red_cursor_cmd = red_cursor_cmd_new(NULL, &mem_info, 0, to_physical(&cursor_cmd));
-    if (red_cursor_cmd != NULL) {
+    auto red_cursor_cmd = red_cursor_cmd_new(NULL, &mem_info, 0, to_physical(&cursor_cmd));
+    if (red_cursor_cmd) {
         /* function does not return errors so there should be no data */
         g_assert_cmpuint(red_cursor_cmd->type, ==, QXL_CURSOR_SET);
         g_assert_cmpuint(red_cursor_cmd->u.set.position.x, ==, 0);
         g_assert_cmpuint(red_cursor_cmd->u.set.position.y, ==, 0);
         g_assert_cmpuint(red_cursor_cmd->u.set.shape.data_size, ==, 0);
-        red_cursor_cmd_unref(red_cursor_cmd);
+        red_cursor_cmd.reset();
     }
     g_test_assert_expected_messages();
 
@@ -247,7 +245,6 @@ static void test_circular_empty_chunks(void)
 static void test_circular_small_chunks(void)
 {
     RedMemSlotInfo mem_info;
-    RedCursorCmd *red_cursor_cmd;
     QXLCursorCmd cursor_cmd;
     QXLCursor *cursor;
     QXLDataChunk *chunks[2];
@@ -271,14 +268,14 @@ static void test_circular_small_chunks(void)
 
     cursor_cmd.u.set.shape = to_physical(cursor);
 
-    red_cursor_cmd = red_cursor_cmd_new(NULL, &mem_info, 0, to_physical(&cursor_cmd));
-    if (red_cursor_cmd != NULL) {
+    auto red_cursor_cmd = red_cursor_cmd_new(NULL, &mem_info, 0, to_physical(&cursor_cmd));
+    if (red_cursor_cmd) {
         /* function does not return errors so there should be no data */
         g_assert_cmpuint(red_cursor_cmd->type, ==, QXL_CURSOR_SET);
         g_assert_cmpuint(red_cursor_cmd->u.set.position.x, ==, 0);
         g_assert_cmpuint(red_cursor_cmd->u.set.position.y, ==, 0);
         g_assert_cmpuint(red_cursor_cmd->u.set.shape.data_size, ==, 0);
-        red_cursor_cmd_unref(red_cursor_cmd);
+        red_cursor_cmd.reset();
     }
     g_test_assert_expected_messages();
 
commit a3656e217d30488be86dd435a6cd541b6743d96a
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Wed Jun 24 19:07:51 2020 +0100

    utils: Add a base light class for reference counting
    
    Similar to shared_ptr_counted but avoid atomic counter and
    polymorphism.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/utils.hpp b/server/utils.hpp
index 063e3f62..e25e1c5e 100644
--- a/server/utils.hpp
+++ b/server/utils.hpp
@@ -430,6 +430,68 @@ inline bool weak_ptr_lock(shared_ptr_counted_weak* p)
 }
 
 
+/**
+ * Utility to help implementing shared_ptr requirements.
+ *
+ * You should inherit publicly this class in order to have base internal reference counting
+ * implementation.
+ *
+ * This class does not use atomic operations and virtual destructor so it's more light than
+ * shared_ptr_counted.
+ *
+ * To avoid issues with inheritance not calling proper destructor the derived objects should
+ * follow this pattern (note the final):
+ *
+ * @code{.cpp}
+ * class Name final: public simple_ptr_counted<Name> {
+ *    ...
+ * }
+ * @endcode
+ *
+ * or
+ *
+ * @code{.cpp}
+ * class Name: public simple_ptr_counted<Name> {
+ *    ...
+ *    virtual ~Name();
+ *    ...
+ * }
+ * @endcode
+ */
+template <typename T>
+class simple_ptr_counted
+{
+public:
+    SPICE_CXX_GLIB_ALLOCATOR
+
+    simple_ptr_counted(): ref_count(0)
+    {
+    }
+private:
+    mutable int ref_count;
+    simple_ptr_counted(const simple_ptr_counted<T>& rhs)=delete;
+    void operator=(const simple_ptr_counted<T>& rhs)=delete;
+    template <typename Q>
+    friend inline void shared_ptr_add_ref(const simple_ptr_counted<Q>*);
+    template <typename Q>
+    friend inline void shared_ptr_unref(const simple_ptr_counted<Q>*);
+};
+
+template <typename T>
+inline void shared_ptr_add_ref(const simple_ptr_counted<T>* p)
+{
+    ++p->ref_count;
+}
+
+template <typename T>
+inline void shared_ptr_unref(const simple_ptr_counted<T>* p)
+{
+    if (--p->ref_count == 0) {
+        delete const_cast<T*>(static_cast<const T*>(p));
+    }
+}
+
+
 } // namespace red
 
 #include "pop-visibility.h"


More information about the Spice-commits mailing list