Hello community,

here is the log from the commit of package neatvnc for openSUSE:Factory checked 
in at 2020-10-05 19:41:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/neatvnc (Old)
 and      /work/SRC/openSUSE:Factory/.neatvnc.new.4249 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "neatvnc"

Mon Oct  5 19:41:48 2020 rev:4 rq:839498 version:0.3.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/neatvnc/neatvnc.changes  2020-08-07 
14:19:53.962381149 +0200
+++ /work/SRC/openSUSE:Factory/.neatvnc.new.4249/neatvnc.changes        
2020-10-05 19:43:10.245789030 +0200
@@ -1,0 +2,8 @@
+Wed Sep 30 08:28:57 UTC 2020 - Dirk Mueller <[email protected]>
+
+- update to 0.3.2:
+  * This release fixes a crash due to incorrect handling of fragmented packets
+  and adds copy & paste support.
+  * This release fixes a bug with tight encoding reported by Jeroen Hofstee
+
+-------------------------------------------------------------------

Old:
----
  v0.2.0.tar.gz

New:
----
  v0.3.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ neatvnc.spec ++++++
--- /var/tmp/diff_new_pack.nGEFEm/_old  2020-10-05 19:43:10.885789656 +0200
+++ /var/tmp/diff_new_pack.nGEFEm/_new  2020-10-05 19:43:10.889789660 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           neatvnc
-Version:        0.2.0
+Version:        0.3.2
 Release:        0
 Summary:        A VNC server library
 License:        ISC

++++++ v0.2.0.tar.gz -> v0.3.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/include/common.h 
new/neatvnc-0.3.2/include/common.h
--- old/neatvnc-0.2.0/include/common.h  2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/include/common.h  2020-09-27 19:31:06.000000000 +0200
@@ -34,6 +34,7 @@
 #define MAX_ENCODINGS 32
 #define MAX_OUTGOING_FRAMES 4
 #define MSG_BUFFER_SIZE 4096
+#define MAX_CUT_TEXT_SIZE 10000000
 
 enum nvnc_client_state {
        VNC_CLIENT_STATE_ERROR = -1,
@@ -58,6 +59,12 @@
        void* userdata;
 };
 
+struct cut_text {
+       char* buffer;
+       size_t length;
+       size_t index;
+};
+
 struct nvnc_client {
        struct nvnc_common common;
        int ref;
@@ -80,6 +87,7 @@
        uint8_t msg_buffer[MSG_BUFFER_SIZE];
        uint32_t known_width;
        uint32_t known_height;
+       struct cut_text cut_text;
 };
 
 LIST_HEAD(nvnc_client_list, nvnc_client);
@@ -96,6 +104,7 @@
        nvnc_pointer_fn pointer_fn;
        nvnc_fb_req_fn fb_req_fn;
        nvnc_client_fn new_client_fn;
+       nvnc_cut_text_fn cut_text_fn;
        struct nvnc_display* display;
 
 #ifdef ENABLE_TLS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/include/enc-util.h 
new/neatvnc-0.3.2/include/enc-util.h
--- old/neatvnc-0.2.0/include/enc-util.h        1970-01-01 01:00:00.000000000 
+0100
+++ new/neatvnc-0.3.2/include/enc-util.h        2020-09-27 19:31:06.000000000 
+0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019 - 2020 Andri Yngvason
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#pragma once
+
+#include "rfb-proto.h"
+
+#include <stdint.h>
+
+struct vec;
+
+int encode_rect_count(struct vec* dst, uint32_t count);
+int encode_rect_head(struct vec* dst, enum rfb_encodings encoding,
+               uint32_t x, uint32_t y, uint32_t width, uint32_t height);
+uint32_t calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/include/neatvnc.h 
new/neatvnc-0.3.2/include/neatvnc.h
--- old/neatvnc-0.2.0/include/neatvnc.h 2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/include/neatvnc.h 2020-09-27 19:31:06.000000000 +0200
@@ -49,6 +49,7 @@
 typedef bool (*nvnc_auth_fn)(const char* username, const char* password,
                              void* userdata);
 typedef void (*nvnc_render_fn)(struct nvnc_display*, struct nvnc_fb*);
+typedef void (*nvnc_cut_text_fn)(struct nvnc*, const char* text, uint32_t len);
 
 extern const char nvnc_version[];
 
@@ -70,6 +71,7 @@
 void nvnc_set_fb_req_fn(struct nvnc* self, nvnc_fb_req_fn);
 void nvnc_set_new_client_fn(struct nvnc* self, nvnc_client_fn);
 void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn);
+void nvnc_set_cut_text_receive_fn(struct nvnc* self, nvnc_cut_text_fn fn);
 
 bool nvnc_has_auth(void);
 int nvnc_enable_auth(struct nvnc* self, const char* privkey_path,
@@ -111,3 +113,5 @@
 int nvnc_check_damage(struct nvnc_fb* fb0, struct nvnc_fb* fb1,
                       int x_hint, int y_hint, int width_hint, int height_hint,
                       nvnc_damage_fn on_check_done, void* userdata);
+
+void nvnc_send_cut_text(struct nvnc*, const char* text, uint32_t len);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/include/rfb-proto.h 
new/neatvnc-0.3.2/include/rfb-proto.h
--- old/neatvnc-0.2.0/include/rfb-proto.h       2020-07-26 15:52:00.000000000 
+0200
+++ new/neatvnc-0.3.2/include/rfb-proto.h       2020-09-27 19:31:06.000000000 
+0200
@@ -140,11 +140,11 @@
        uint16_t y;
 } RFB_PACKED;
 
-struct rfb_client_cut_text_msg {
+struct rfb_cut_text_msg {
        uint8_t type;
        uint8_t padding[3];
        uint32_t length;
-       char test[0];
+       char text[0];
 } RFB_PACKED;
 
 struct rfb_server_fb_rect {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/include/tight.h 
new/neatvnc-0.3.2/include/tight.h
--- old/neatvnc-0.2.0/include/tight.h   2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/include/tight.h   2020-09-27 19:31:06.000000000 +0200
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include "rfb-proto.h"
+#include "vec.h"
+
 #include <unistd.h>
 #include <stdint.h>
 #include <zlib.h>
@@ -25,6 +28,8 @@
 struct pixman_region16;
 struct aml_work;
 
+typedef void (*tight_done_fn)(struct vec* frame, void*);
+
 enum tight_quality {
        TIGHT_QUALITY_UNSPEC = 0,
        TIGHT_QUALITY_LOSSLESS,
@@ -44,17 +49,17 @@
        z_stream zs[4];
        struct aml_work* zs_worker[4];
 
-       const struct rfb_pixel_format* dfmt;
-       const struct rfb_pixel_format* sfmt;
-       const struct nvnc_fb* fb;
+       struct rfb_pixel_format dfmt;
+       struct rfb_pixel_format sfmt;
+       struct nvnc_fb* fb;
 
        uint32_t n_rects;
        uint32_t n_jobs;
 
-       struct vec* dst;
+       struct vec dst;
 
-       pthread_mutex_t wait_mutex;
-       pthread_cond_t wait_cond;
+       tight_done_fn on_frame_done;
+       void* userdata;
 };
 
 int tight_encoder_init(struct tight_encoder* self, uint32_t width,
@@ -64,9 +69,10 @@
 int tight_encoder_resize(struct tight_encoder* self, uint32_t width,
                uint32_t height);
 
-int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
+int tight_encode_frame(struct tight_encoder* self,
                const struct rfb_pixel_format* dfmt,
-               const struct nvnc_fb* src,
+               struct nvnc_fb* src,
                const struct rfb_pixel_format* sfmt,
                struct pixman_region16* damage,
-               enum tight_quality quality);
+               enum tight_quality quality,
+               tight_done_fn on_done, void* userdata);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/meson.build 
new/neatvnc-0.3.2/meson.build
--- old/neatvnc-0.2.0/meson.build       2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/meson.build       2020-09-27 19:31:06.000000000 +0200
@@ -1,7 +1,7 @@
 project(
        'neatvnc',
        'c',
-       version: '0.2.0',
+       version: '0.3.2',
        license: 'ISC',
        default_options: [
                'c_std=gnu11',
@@ -66,6 +66,7 @@
        'src/stream.c',
        'src/display.c',
        'src/tight.c',
+       'src/enc-util.c',
 ]
 
 dependencies = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/src/enc-util.c 
new/neatvnc-0.3.2/src/enc-util.c
--- old/neatvnc-0.2.0/src/enc-util.c    1970-01-01 01:00:00.000000000 +0100
+++ new/neatvnc-0.3.2/src/enc-util.c    2020-09-27 19:31:06.000000000 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 - 2020 Andri Yngvason
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "enc-util.h"
+#include "rfb-proto.h"
+#include "vec.h"
+
+#include <arpa/inet.h>
+
+int encode_rect_count(struct vec* dst, uint32_t count)
+{
+       struct rfb_server_fb_update_msg msg = {
+               .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
+               .n_rects = htons(count),
+       };
+
+       return vec_append(dst, &msg, sizeof(msg));
+}
+
+int encode_rect_head(struct vec* dst, enum rfb_encodings encoding,
+               uint32_t x, uint32_t y, uint32_t width, uint32_t height)
+{
+       struct rfb_server_fb_rect head = {
+               .encoding = htonl(encoding),
+               .x = htons(x),
+               .y = htons(y),
+               .width = htons(width),
+               .height = htons(height),
+       };
+
+       return vec_append(dst, &head, sizeof(head));
+}
+
+uint32_t calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt)
+{
+       return fmt->bits_per_pixel == 32 ? fmt->depth / 8
+                                        : fmt->bits_per_pixel / 8;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/src/raw-encoding.c 
new/neatvnc-0.3.2/src/raw-encoding.c
--- old/neatvnc-0.2.0/src/raw-encoding.c        2020-07-26 15:52:00.000000000 
+0200
+++ new/neatvnc-0.3.2/src/raw-encoding.c        2020-09-27 19:31:06.000000000 
+0200
@@ -20,6 +20,7 @@
 #include "fb.h"
 #include "pixels.h"
 #include "raw-encoding.h"
+#include "enc-util.h"
 
 #include <pixman.h>
 
@@ -31,15 +32,8 @@
 {
        int rc = -1;
 
-       struct rfb_server_fb_rect rect = {
-               .encoding = htonl(RFB_ENCODING_RAW),
-               .x = htons(x_start),
-               .y = htons(y_start),
-               .width = htons(width),
-               .height = htons(height),
-       };
-
-       rc = vec_append(dst, &rect, sizeof(rect));
+       rc = encode_rect_head(dst, RFB_ENCODING_RAW, x_start, y_start, width,
+                       height);
        if (rc < 0)
                return -1;
 
@@ -77,16 +71,11 @@
                n_rects = 1;
        }
 
-       struct rfb_server_fb_update_msg head = {
-               .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
-               .n_rects = htons(n_rects),
-       };
-
        rc = vec_reserve(dst, src->width * src->height * 4);
        if (rc < 0)
                return -1;
 
-       rc = vec_append(dst, &head, sizeof(head));
+       rc = encode_rect_count(dst, n_rects);
        if (rc < 0)
                return -1;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/src/server.c 
new/neatvnc-0.3.2/src/server.c
--- old/neatvnc-0.2.0/src/server.c      2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/src/server.c      2020-09-27 19:31:06.000000000 +0200
@@ -69,7 +69,12 @@
        struct nvnc_fb* fb;
 };
 
-int schedule_client_update_fb(struct nvnc_client* client);
+int schedule_client_update_fb(struct nvnc_client* client,
+               struct pixman_region16* damage);
+static int send_desktop_resize(struct nvnc_client* client, struct nvnc_fb* fb);
+static enum rfb_encodings choose_frame_encoding(struct nvnc_client* client);
+static enum tight_quality client_get_tight_quality(struct nvnc_client* client);
+static void on_tight_encode_frame_done(struct vec* frame, void* userdata);
 
 #if defined(GIT_VERSION)
 EXPORT const char nvnc_version[] = GIT_VERSION;
@@ -92,6 +97,7 @@
        tight_encoder_destroy(&client->tight_encoder);
        deflateEnd(&client->z_stream);
        pixman_region_fini(&client->damage);
+       free(client->cut_text.buffer);
        free(client);
 }
 
@@ -489,7 +495,9 @@
 
 static void process_fb_update_requests(struct nvnc_client* client)
 {
-       if (!client->server->display || !client->server->display->buffer)
+       struct nvnc* server = client->server;
+
+       if (!server->display || !server->display->buffer)
                return;
 
        if (client->net_stream->state == STREAM_STATE_CLOSED)
@@ -501,8 +509,57 @@
        if (client->is_updating || client->n_pending_requests == 0)
                return;
 
+       struct nvnc_fb* fb = client->server->display->buffer;
+       assert(fb);
+
+       if (!client->has_pixfmt) {
+               rfb_pixfmt_from_fourcc(&client->pixfmt, fb->fourcc_format);
+               client->has_pixfmt = true;
+       }
+
+       if (fb->width != client->known_width
+           || fb->height != client->known_height)
+               send_desktop_resize(client, fb);
+
+       DTRACE_PROBE1(neatvnc, update_fb_start, client);
+
+       /* The client's damage is exchanged for an empty one */
+       struct pixman_region16 damage = client->damage;
+       pixman_region_init(&client->damage);
+
        client->is_updating = true;
-       if (schedule_client_update_fb(client) < 0)
+
+       int rc;
+       enum rfb_encodings encoding = choose_frame_encoding(client);
+
+       // TODO: Check the return value
+       struct rfb_pixel_format server_fmt;
+       rfb_pixfmt_from_fourcc(&server_fmt, fb->fourcc_format);
+
+       switch (encoding) {
+       case RFB_ENCODING_RAW:
+       case RFB_ENCODING_ZRLE:
+               rc = schedule_client_update_fb(client, &damage);
+               break;
+       case RFB_ENCODING_TIGHT:
+               client_ref(client);
+
+               enum tight_quality quality = client_get_tight_quality(client);
+               rc = tight_encode_frame(&client->tight_encoder, &client->pixfmt,
+                               fb, &server_fmt, &damage, quality,
+                               on_tight_encode_frame_done, client);
+
+               if (rc < 0)
+                       client_unref(client);
+
+               pixman_region_fini(&damage);
+               break;
+       default:
+               rc = -1;
+               break;
+       }
+
+       if (rc < 0)
                client->is_updating = false;
 }
 
@@ -584,20 +641,113 @@
        return sizeof(*msg);
 }
 
+EXPORT
+void nvnc_send_cut_text(struct nvnc* server, const char* text, uint32_t len)
+{
+       struct rfb_cut_text_msg msg;
+
+       msg.type = RFB_SERVER_TO_CLIENT_SERVER_CUT_TEXT;
+       msg.length = htonl(len);
+
+       struct nvnc_client* client;
+       LIST_FOREACH (client, &server->clients, link) {
+               stream_write(client->net_stream, &msg, sizeof(msg), NULL, NULL);
+               stream_write(client->net_stream, text, len, NULL, NULL);
+       }
+}
+
 static int on_client_cut_text(struct nvnc_client* client)
 {
-       struct rfb_client_cut_text_msg* msg =
-               (struct rfb_client_cut_text_msg*)(client->msg_buffer +
-                                                 client->buffer_index);
+       struct nvnc* server = client->server;
+       nvnc_cut_text_fn fn = server->cut_text_fn;
+       struct rfb_cut_text_msg* msg =
+               (struct rfb_cut_text_msg*)(client->msg_buffer +
+                                          client->buffer_index);
 
-       if (client->buffer_len - client->buffer_index < sizeof(*msg))
+       size_t left_to_process = client->buffer_len - client->buffer_index;
+
+       if (left_to_process < sizeof(*msg))
                return 0;
 
        uint32_t length = ntohl(msg->length);
+       uint32_t max_length = MAX_CUT_TEXT_SIZE;
+
+       /* Messages greater than this size are unsupported */
+       if (length > max_length) {
+               log_error("Copied text length (%d) is greater than max 
supported length (%d)\n",
+                       length, max_length);
+               stream_close(client->net_stream);
+               client_unref(client);
+               return 0;
+       }
+
+       size_t msg_size = sizeof(*msg) + length;
+
+       if (msg_size <= left_to_process) {
+               if (fn)
+                       fn(server, msg->text, length);
+
+               return msg_size;
+       }
 
-       // TODO
+       assert(!client->cut_text.buffer);
 
-       return sizeof(*msg) + length;
+       client->cut_text.buffer = malloc(length);
+       if (!client->cut_text.buffer) {
+               log_error("OOM: %m\n");
+               stream_close(client->net_stream);
+               client_unref(client);
+               return 0;
+       }
+
+       size_t partial_size = left_to_process - sizeof(*msg);
+
+       memcpy(client->cut_text.buffer, msg->text, partial_size);
+
+       client->cut_text.length = length;
+       client->cut_text.index = partial_size;
+
+       return left_to_process;
+}
+
+static void process_big_cut_text(struct nvnc_client* client)
+{
+       struct nvnc* server = client->server;
+       nvnc_cut_text_fn fn = server->cut_text_fn;
+
+       assert(client->cut_text.length > client->cut_text.index);
+
+       void* start = client->cut_text.buffer + client->cut_text.index;
+       size_t space = client->cut_text.length - client->cut_text.index;
+
+       space = MIN(space, MSG_BUFFER_SIZE);
+
+       ssize_t n_read = stream_read(client->net_stream, start, space);
+
+       if (n_read == 0)
+               return;
+
+       if (n_read < 0) {
+               if (errno != EAGAIN) {
+                       log_debug("Client connection error: %p (ref %d)\n",
+                                 client, client->ref);
+                       stream_close(client->net_stream);
+                       client_unref(client);
+               }
+
+               return;
+       }
+
+       client->cut_text.index += n_read;
+
+       if (client->cut_text.index != client->cut_text.length)
+               return;
+
+       if (fn)
+               fn(server, client->cut_text.buffer, client->cut_text.length);
+
+       free(client->cut_text.buffer);
+       client->cut_text.buffer = NULL;
 }
 
 static int on_client_message(struct nvnc_client* client)
@@ -670,6 +820,11 @@
                return;
        }
 
+       if (client->cut_text.buffer) {
+               process_big_cut_text(client);
+               return;
+       }
+
        assert(client->buffer_index == 0);
 
        void* start = client->msg_buffer + client->buffer_len;
@@ -703,9 +858,9 @@
 
        assert(client->buffer_index <= client->buffer_len);
 
-       memmove(client->msg_buffer, client->msg_buffer + client->buffer_index,
-               client->buffer_index);
        client->buffer_len -= client->buffer_index;
+       memmove(client->msg_buffer, client->msg_buffer + client->buffer_index,
+               client->buffer_len);
        client->buffer_index = 0;
 }
 
@@ -991,21 +1146,13 @@
 
        enum rfb_encodings encoding = choose_frame_encoding(client);
 
-       if (!client->has_pixfmt) {
-               rfb_pixfmt_from_fourcc(&client->pixfmt, fb->fourcc_format);
-               client->has_pixfmt = true;
-       }
-
        switch (encoding) {
        case RFB_ENCODING_RAW:
                raw_encode_frame(&update->frame, &client->pixfmt, fb,
                                 &update->server_fmt, &update->region);
                break;
-       case RFB_ENCODING_TIGHT:;
-               enum tight_quality quality = client_get_tight_quality(client);
-               tight_encode_frame(&client->tight_encoder, &update->frame,
-                               &client->pixfmt, fb, &update->server_fmt,
-                               &update->region, quality);
+       case RFB_ENCODING_TIGHT:
+               abort();
                break;
        case RFB_ENCODING_ZRLE:
                zrle_encode_frame(&client->z_stream, &update->frame,
@@ -1017,14 +1164,8 @@
        }
 }
 
-static void on_client_update_fb_done(void* work)
+static void finish_fb_update(struct nvnc_client* client, struct vec* frame)
 {
-       struct fb_update_work* update = aml_get_userdata(work);
-       struct nvnc_client* client = update->client;
-       struct vec* frame = &update->frame;
-
-       nvnc_fb_unref(update->fb);
-
        client_ref(client);
 
        if (client->net_stream->state != STREAM_STATE_CLOSED) {
@@ -1042,6 +1183,24 @@
        client->n_pending_requests--;
 
        DTRACE_PROBE1(neatvnc, update_fb_done, client);
+}
+
+static void on_tight_encode_frame_done(struct vec* frame, void* userdata)
+{
+       struct nvnc_client* client = userdata;
+       finish_fb_update(client, frame);
+       client_unref(client);
+}
+
+static void on_client_update_fb_done(void* work)
+{
+       struct fb_update_work* update = aml_get_userdata(work);
+       struct nvnc_client* client = update->client;
+       struct vec* frame = &update->frame;
+
+       nvnc_fb_unref(update->fb);
+
+       finish_fb_update(client, frame);
 
        pixman_region_fini(&update->region);
 
@@ -1081,13 +1240,12 @@
        return 0;
 }
 
-int schedule_client_update_fb(struct nvnc_client* client)
+int schedule_client_update_fb(struct nvnc_client* client,
+               struct pixman_region16* damage)
 {
        struct nvnc_fb* fb = client->server->display->buffer;
        assert(fb);
 
-       DTRACE_PROBE1(neatvnc, update_fb_start, client);
-
        struct fb_update_work* work = calloc(1, sizeof(*work));
        if (!work)
                return -1;
@@ -1097,15 +1255,7 @@
 
        work->client = client;
        work->fb = fb;
-
-       if (fb->width != client->known_width
-           || fb->height != client->known_height)
-               if (send_desktop_resize(client, fb) < 0)
-                       goto resize_failure;
-
-       /* The client's damage is exchanged for an empty one */
-       work->region = client->damage;
-       pixman_region_init(&client->damage);
+       work->region = *damage;
 
        int rc = vec_init(&work->frame, fb->width * fb->height * 3 / 2);
        if (rc < 0)
@@ -1138,7 +1288,6 @@
        vec_destroy(&work->frame);
 vec_failure:
 pixfmt_failure:
-resize_failure:
        free(work);
        return -1;
 }
@@ -1198,6 +1347,12 @@
 }
 
 EXPORT
+void nvnc_set_cut_text_receive_fn(struct nvnc* self, nvnc_cut_text_fn fn)
+{
+       self->cut_text_fn = fn;
+}
+
+EXPORT
 void nvnc_add_display(struct nvnc* self, struct nvnc_display* display)
 {
        if (self->display) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/src/tight.c 
new/neatvnc-0.3.2/src/tight.c
--- old/neatvnc-0.2.0/src/tight.c       2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/src/tight.c       2020-09-27 19:31:06.000000000 +0200
@@ -22,6 +22,7 @@
 #include "logging.h"
 #include "tight.h"
 #include "config.h"
+#include "enc-util.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -72,6 +73,7 @@
 
 static void do_tight_zs_work(void*);
 static void on_tight_zs_work_done(void*);
+static int schedule_tight_finish(struct tight_encoder* self);
 
 static int tight_encoder_init_stream(z_stream* zs)
 {
@@ -157,21 +159,13 @@
        tight_init_zs_worker(self, 2);
        tight_init_zs_worker(self, 3);
 
-       pthread_mutex_init(&self->wait_mutex, NULL);
-       pthread_cond_init(&self->wait_cond, NULL);
-
-       // One worker is blocked while other workers are encoding, so at least
-       // 2 are required.
-       aml_require_workers(aml_get_default(), 2);
+       aml_require_workers(aml_get_default(), 1);
 
        return 0;
 }
 
 void tight_encoder_destroy(struct tight_encoder* self)
 {
-       pthread_cond_destroy(&self->wait_cond);
-       pthread_mutex_destroy(&self->wait_mutex);
-
        aml_unref(self->zs_worker[3]);
        aml_unref(self->zs_worker[2]);
        aml_unref(self->zs_worker[1]);
@@ -223,12 +217,6 @@
                vec_fast_append_8(dst, (size >> 14) & 0xff);
 }
 
-static int calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt)
-{
-       return fmt->bits_per_pixel == 32 ? fmt->depth / 8
-                                        : fmt->bits_per_pixel / 8;
-}
-
 static int tight_deflate(struct tight_tile* tile, void* src,
                         size_t len, z_stream* zs, bool flush)
 {
@@ -261,7 +249,7 @@
        z_stream* zs = &self->zs[zs_index];
        tile->type = TIGHT_BASIC | TIGHT_STREAM(zs_index);
 
-       int bytes_per_cpixel = calc_bytes_per_cpixel(self->dfmt);
+       int bytes_per_cpixel = calc_bytes_per_cpixel(&self->dfmt);
        assert(bytes_per_cpixel <= 4);
        uint8_t row[TSL * 4];
 
@@ -269,7 +257,7 @@
        if (bytes_per_cpixel == 3)
                rfb_pixfmt_from_fourcc(&cfmt, DRM_FORMAT_XBGR8888);
        else
-               memcpy(&cfmt, self->dfmt, sizeof(cfmt));
+               memcpy(&cfmt, &self->dfmt, sizeof(cfmt));
 
        uint32_t* addr = nvnc_fb_get_addr(self->fb);
        uint32_t stride = nvnc_fb_get_width(self->fb);
@@ -277,8 +265,8 @@
        // TODO: Limit width and hight to the sides
        for (uint32_t y = y_start; y < y_start + height; ++y) {
                void* img = addr + x + y * stride;
-               pixel32_to_cpixel(row, &cfmt, img, self->sfmt, bytes_per_cpixel,
-                               width);
+               pixel32_to_cpixel(row, &cfmt, img, &self->sfmt,
+                               bytes_per_cpixel, width);
 
                // TODO What to do if the buffer fills up?
                if (tight_deflate(tile, row, bytes_per_cpixel * width,
@@ -397,16 +385,6 @@
        tile->state = TIGHT_TILE_ENCODED;
 }
 
-static int tight_encode_rect_count(struct tight_encoder* self)
-{
-       struct rfb_server_fb_update_msg msg = {
-               .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
-               .n_rects = htons(self->n_rects),
-       };
-
-       return vec_append(self->dst, &msg, sizeof(msg));
-}
-
 static void do_tight_zs_work(void* obj)
 {
        struct tight_zs_worker_ctx* ctx = aml_get_userdata(obj);
@@ -424,10 +402,10 @@
        struct tight_zs_worker_ctx* ctx = aml_get_userdata(obj);
        struct tight_encoder* self = ctx->encoder;
 
-       pthread_mutex_lock(&self->wait_mutex);
-       if (--self->n_jobs == 0)
-               pthread_cond_signal(&self->wait_cond);
-       pthread_mutex_unlock(&self->wait_mutex);
+       if (--self->n_jobs == 0) {
+               nvnc_fb_unref(self->fb);
+               schedule_tight_finish(self);
+       }
 }
 
 static int tight_schedule_zs_work(struct tight_encoder* self, int index)
@@ -441,17 +419,11 @@
 
 static int tight_schedule_encoding_jobs(struct tight_encoder* self)
 {
-       int rc = -1;
-
-       pthread_mutex_lock(&self->wait_mutex);
        for (int i = 0; i < 4; ++i)
                if (tight_schedule_zs_work(self, i) < 0)
-                       goto failure;
+                       return -1;
 
-       rc = 0;
-failure:
-       pthread_mutex_unlock(&self->wait_mutex);
-       return rc;
+       return 0;
 }
 
 static void tight_finish_tile(struct tight_encoder* self,
@@ -465,18 +437,11 @@
        uint32_t width = tight_tile_width(self, x);
        uint32_t height = tight_tile_height(self, y);
 
-       struct rfb_server_fb_rect rect = {
-               .encoding = htonl(RFB_ENCODING_TIGHT),
-               .x = htons(x),
-               .y = htons(y),
-               .width = htons(width),
-               .height = htons(height),
-       };
-
-       vec_append(self->dst, &rect, sizeof(rect));
-       vec_append(self->dst, &tile->type, sizeof(tile->type));
-       tight_encode_size(self->dst, tile->size);
-       vec_append(self->dst, tile->buffer, tile->size);
+       encode_rect_head(&self->dst, RFB_ENCODING_TIGHT, x, y, width, height);
+
+       vec_append(&self->dst, &tile->type, sizeof(tile->type));
+       tight_encode_size(&self->dst, tile->size);
+       vec_append(&self->dst, tile->buffer, tile->size);
 
        tile->state = TIGHT_TILE_READY;
 }
@@ -489,36 +454,64 @@
                                tight_finish_tile(self, x, y);
 }
 
-int tight_encode_frame(struct tight_encoder* self, struct vec* dst,
+static void do_tight_finish(void* obj)
+{
+       // TODO: Make sure there's no use-after-free here
+       struct tight_encoder* self = aml_get_userdata(obj);
+       tight_finish(self);
+}
+
+static void on_tight_finished(void* obj)
+{
+       struct tight_encoder* self = aml_get_userdata(obj);
+       self->on_frame_done(&self->dst, self->userdata);
+}
+
+static int schedule_tight_finish(struct tight_encoder* self)
+{
+       struct aml_work* work = aml_work_new(do_tight_finish, on_tight_finished,
+                       self, NULL);
+       if (!work)
+               return -1;
+
+       int rc = aml_start(aml_get_default(), work);
+       aml_unref(work);
+       return rc;
+}
+
+int tight_encode_frame(struct tight_encoder* self,
                const struct rfb_pixel_format* dfmt,
-               const struct nvnc_fb* src,
+               struct nvnc_fb* src,
                const struct rfb_pixel_format* sfmt,
                struct pixman_region16* damage,
-               enum tight_quality quality)
+               enum tight_quality quality,
+               tight_done_fn on_done, void* userdata)
 {
-       self->dfmt = dfmt;
-       self->sfmt = sfmt;
+       memcpy(&self->dfmt, dfmt, sizeof(self->dfmt));
+       memcpy(&self->sfmt, sfmt, sizeof(self->sfmt));
        self->fb = src;
-       self->dst = dst;
        self->quality = quality;
+       self->on_frame_done = on_done;
+       self->userdata = userdata;
 
-       vec_clear(dst);
+       uint32_t width = nvnc_fb_get_width(src);
+       uint32_t height = nvnc_fb_get_height(src);
+       int rc = vec_init(&self->dst, width * height * 4);
+       if (rc < 0)
+               return -1;
 
        self->n_rects = tight_apply_damage(self, damage);
        assert(self->n_rects > 0);
 
-       tight_encode_rect_count(self);
+       encode_rect_count(&self->dst, self->n_rects);
 
-       if (tight_schedule_encoding_jobs(self) < 0)
-               return -1;
+       nvnc_fb_ref(self->fb);
 
-       // TODO Change architecture so we don't have to wait here
-       pthread_mutex_lock(&self->wait_mutex);
-       while (self->n_jobs != 0)
-               pthread_cond_wait(&self->wait_cond, &self->wait_mutex);
-       pthread_mutex_unlock(&self->wait_mutex);
-
-       tight_finish(self);
+       if (tight_schedule_encoding_jobs(self) < 0) {
+               nvnc_fb_unref(self->fb);
+               vec_destroy(&self->dst);
+               return -1;
+       }
 
        return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.2.0/src/zrle.c new/neatvnc-0.3.2/src/zrle.c
--- old/neatvnc-0.2.0/src/zrle.c        2020-07-26 15:52:00.000000000 +0200
+++ new/neatvnc-0.3.2/src/zrle.c        2020-09-27 19:31:06.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Andri Yngvason
+ * Copyright (c) 2019 - 2020 Andri Yngvason
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,6 +20,7 @@
 #include "neatvnc.h"
 #include "pixels.h"
 #include "fb.h"
+#include "enc-util.h"
 
 #include <stdint.h>
 #include <unistd.h>
@@ -43,12 +44,6 @@
        return -1;
 }
 
-static inline int calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt)
-{
-       return fmt->bits_per_pixel == 32 ? fmt->depth / 8
-                                        : fmt->bits_per_pixel / 8;
-}
-
 static int zrle_get_tile_palette(uint32_t* palette, const uint32_t* src,
                                  size_t length)
 {
@@ -222,15 +217,7 @@
        if (vec_init(&in, 1 + bytes_per_cpixel * TILE_LENGTH * TILE_LENGTH) < 0)
                goto failure;
 
-       struct rfb_server_fb_rect rect = {
-               .encoding = htonl(RFB_ENCODING_ZRLE),
-               .x = htons(x),
-               .y = htons(y),
-               .width = htons(width),
-               .height = htons(height),
-       };
-
-       r = vec_append(out, &rect, sizeof(rect));
+       r = encode_rect_head(out, RFB_ENCODING_ZRLE, x, y, width, height);
        if (r < 0)
                goto failure;
 
@@ -289,12 +276,7 @@
                n_rects = 1;
        }
 
-       struct rfb_server_fb_update_msg head = {
-               .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
-               .n_rects = htons(n_rects),
-       };
-
-       rc = vec_append(dst, &head, sizeof(head));
+       rc = encode_rect_count(dst, n_rects);
        if (rc < 0)
                return -1;
 


Reply via email to