From f3e09fd6229355db504b55007be85394ef0ad2a0 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sun, 12 Apr 2020 18:16:19 +0000 Subject: [PATCH] Prepare API for multi-display support These changes are made now to make it possible to add multi-display support in the future while keeping the public interface stable. --- examples/draw.c | 29 ++++++++---- examples/png-server.c | 11 ++++- include/common.h | 7 ++- include/display.h | 33 ++++++++++++++ include/neatvnc.h | 25 +++++++--- meson.build | 1 + src/display.c | 103 ++++++++++++++++++++++++++++++++++++++++++ src/server.c | 78 ++++++++++++++++---------------- 8 files changed, 228 insertions(+), 59 deletions(-) create mode 100644 include/display.h create mode 100644 src/display.c diff --git a/examples/draw.c b/examples/draw.c index 591d952..418a9d4 100644 --- a/examples/draw.c +++ b/examples/draw.c @@ -35,6 +35,7 @@ struct coord { }; struct draw { + struct nvnc_display* display; struct nvnc_fb* fb; struct coord coord[MAX_COORD]; int index; @@ -47,8 +48,8 @@ int coord_distance_between(struct coord a, struct coord b) return round(sqrt(x * x + y * y)); } -void draw_dot(struct nvnc* nvnc, struct nvnc_fb* fb, struct coord coord, - int radius, uint32_t colour) +void draw_dot(struct nvnc_display* display, struct nvnc_fb* fb, + struct coord coord, int radius, uint32_t colour) { uint32_t* image = nvnc_fb_get_addr(fb); int width = nvnc_fb_get_width(fb); @@ -64,7 +65,7 @@ void draw_dot(struct nvnc* nvnc, struct nvnc_fb* fb, struct coord coord, struct pixman_region16 region; pixman_region_init_rect(®ion, start.x, start.y, stop.x - start.x, stop.y - start.y); - nvnc_damage_region(nvnc, ®ion); + nvnc_display_damage_region(display, ®ion); pixman_region_fini(®ion); /* The brute force method. ;) */ @@ -82,7 +83,7 @@ void on_pointer_event(struct nvnc_client* client, uint16_t x, uint16_t y, if (!(buttons & NVNC_BUTTON_LEFT)) return; - struct nvnc* server = nvnc_get_server(client); + struct nvnc* server = nvnc_client_get_server(client); assert(server); struct draw* draw = nvnc_get_userdata(server); @@ -101,17 +102,20 @@ void on_pointer_event(struct nvnc_client* client, uint16_t x, uint16_t y, struct pixman_region16 region; pixman_region_init_rect(®ion, 0, 0, width, height); pixman_region_intersect_rect(®ion, ®ion, x, y, 1, 1); - nvnc_damage_region(server, ®ion); + nvnc_display_damage_region(draw->display, ®ion); pixman_region_fini(®ion); } -void on_render(struct nvnc* server, struct nvnc_fb* fb) +void on_render(struct nvnc_display* display, struct nvnc_fb* fb) { + struct nvnc* server = nvnc_display_get_server(display); + assert(server); + struct draw* draw = nvnc_get_userdata(server); assert(draw); for (int i = 0; i < draw->index; ++i) - draw_dot(server, fb, draw->coord[i], 16, 0); + draw_dot(draw->display, fb, draw->coord[i], 16, 0); draw->index = 0; } @@ -138,12 +142,18 @@ int main(int argc, char* argv[]) aml_set_default(aml); struct nvnc* server = nvnc_open("127.0.0.1", 5900); + assert(server); + + draw.display = nvnc_display_new(0, 0); + assert(draw.display); + nvnc_display_set_buffer(draw.display, draw.fb); + nvnc_display_set_render_fn(draw.display, on_render); + + nvnc_add_display(server, draw.display); nvnc_set_name(server, "Draw"); nvnc_set_pointer_fn(server, on_pointer_event); nvnc_set_userdata(server, &draw); - nvnc_set_buffer(server, draw.fb); - nvnc_set_render_fn(server, on_render); struct aml_signal* sig = aml_signal_new(SIGINT, on_sigint, NULL, NULL); aml_start(aml_get_default(), sig); @@ -152,6 +162,7 @@ int main(int argc, char* argv[]) aml_run(aml); nvnc_close(server); + nvnc_display_unref(draw.display); nvnc_fb_unref(draw.fb); aml_unref(aml); } diff --git a/examples/png-server.c b/examples/png-server.c index d7357ed..054ad33 100644 --- a/examples/png-server.c +++ b/examples/png-server.c @@ -48,11 +48,17 @@ int main(int argc, char* argv[]) aml_set_default(aml); struct nvnc* server = nvnc_open("127.0.0.1", 5900); + assert(server); - nvnc_set_buffer(server, fb); + struct nvnc_display* display = nvnc_display_new(0, 0); + assert(display); + + nvnc_display_set_buffer(display, fb); + + nvnc_add_display(server, display); nvnc_set_name(server, file); - nvnc_damage_whole(server); + nvnc_display_damage_whole(display); struct aml_signal* sig = aml_signal_new(SIGINT, on_sigint, NULL, NULL); aml_start(aml_get_default(), sig); @@ -61,6 +67,7 @@ int main(int argc, char* argv[]) aml_run(aml); nvnc_close(server); + nvnc_display_unref(display); nvnc_fb_unref(fb); aml_unref(aml); } diff --git a/include/common.h b/include/common.h index 207f2e7..0d7754f 100644 --- a/include/common.h +++ b/include/common.h @@ -52,6 +52,7 @@ struct nvnc; struct stream; struct aml_handler; struct aml_idle; +struct nvnc_display; struct nvnc_common { void* userdata; @@ -93,8 +94,7 @@ struct nvnc { nvnc_pointer_fn pointer_fn; nvnc_fb_req_fn fb_req_fn; nvnc_client_fn new_client_fn; - nvnc_render_fn render_fn; - struct nvnc_fb* buffer; + struct nvnc_display* display; #ifdef ENABLE_TLS gnutls_certificate_credentials_t tls_creds; @@ -102,3 +102,6 @@ struct nvnc { void* auth_ud; #endif }; + +void nvnc__damage_region(struct nvnc* self, + const struct pixman_region16* damage); diff --git a/include/display.h b/include/display.h new file mode 100644 index 0000000..924a3ea --- /dev/null +++ b/include/display.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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 "neatvnc.h" + +#include +#include + +struct nvnc; +struct nvnc_fb; + +struct nvnc_display { + int ref; + struct nvnc* server; + uint16_t x_pos, y_pos; + struct nvnc_fb* buffer; + nvnc_render_fn render_fn; +}; diff --git a/include/neatvnc.h b/include/neatvnc.h index 389ebf3..fd115a5 100644 --- a/include/neatvnc.h +++ b/include/neatvnc.h @@ -21,6 +21,7 @@ struct nvnc; struct nvnc_client; +struct nvnc_display; struct nvnc_fb; struct pixman_region16; @@ -47,17 +48,18 @@ typedef void (*nvnc_client_fn)(struct nvnc_client*); typedef void (*nvnc_damage_fn)(struct pixman_region16* damage, void* userdata); typedef bool (*nvnc_auth_fn)(const char* username, const char* password, void* userdata); -typedef void (*nvnc_render_fn)(struct nvnc*, struct nvnc_fb*); +typedef void (*nvnc_render_fn)(struct nvnc_display*, struct nvnc_fb*); struct nvnc* nvnc_open(const char* addr, uint16_t port); void nvnc_close(struct nvnc* self); +void nvnc_add_display(struct nvnc*, struct nvnc_display*); +void nvnc_remove_display(struct nvnc*, struct nvnc_display*); + void nvnc_set_userdata(void* self, void* userdata); void* nvnc_get_userdata(const void* self); -struct nvnc* nvnc_get_server(const struct nvnc_client* client); - -void nvnc_set_buffer(struct nvnc*, struct nvnc_fb*); +struct nvnc* nvnc_client_get_server(const struct nvnc_client* client); void nvnc_set_name(struct nvnc* self, const char* name); @@ -65,7 +67,6 @@ void nvnc_set_key_fn(struct nvnc* self, nvnc_key_fn); void nvnc_set_pointer_fn(struct nvnc* self, nvnc_pointer_fn); 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_render_fn(struct nvnc* self, nvnc_render_fn fn); void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn); bool nvnc_has_auth(void); @@ -86,8 +87,18 @@ uint16_t nvnc_fb_get_width(const struct nvnc_fb* fb); uint16_t nvnc_fb_get_height(const struct nvnc_fb* fb); uint32_t nvnc_fb_get_fourcc_format(const struct nvnc_fb* fb); -void nvnc_damage_region(struct nvnc*, const struct pixman_region16* damage); -void nvnc_damage_whole(struct nvnc*); +struct nvnc_display* nvnc_display_new(uint16_t x_pos, uint16_t y_pos); +void nvnc_display_ref(struct nvnc_display*); +void nvnc_display_unref(struct nvnc_display*); + +struct nvnc* nvnc_display_get_server(const struct nvnc_display*); + +void nvnc_display_set_render_fn(struct nvnc_display* self, nvnc_render_fn fn); +void nvnc_display_set_buffer(struct nvnc_display*, struct nvnc_fb*); + +void nvnc_display_damage_region(struct nvnc_display*, + const struct pixman_region16*); +void nvnc_display_damage_whole(struct nvnc_display*); /* * Find the regions that differ between fb0 and fb1. Regions outside the hinted diff --git a/meson.build b/meson.build index f5b2354..900e7b5 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,7 @@ sources = [ 'src/fb.c', 'src/rcbuf.c', 'src/stream.c', + 'src/display.c', ] dependencies = [ diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..46aa1c7 --- /dev/null +++ b/src/display.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 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 "display.h" +#include "neatvnc.h" +#include "common.h" + +#include +#include + +#define EXPORT __attribute__((visibility("default"))) + +EXPORT +struct nvnc_display* nvnc_display_new(uint16_t x_pos, uint16_t y_pos) +{ + struct nvnc_display* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->ref = 1; + self->x_pos = x_pos; + self->y_pos = y_pos; + + return self; +} + +void nvnc__display_free(struct nvnc_display* self) +{ + if (self->buffer) + nvnc_fb_unref(self->buffer); + free(self); +} + +EXPORT +void nvnc_display_ref(struct nvnc_display* self) +{ + self->ref++; +} + +EXPORT +void nvnc_display_unref(struct nvnc_display* self) +{ + if (--self->ref == 0) + nvnc__display_free(self); +} + +EXPORT +struct nvnc* nvnc_display_get_server(const struct nvnc_display* self) +{ + return self->server; +} + +EXPORT +void nvnc_display_set_buffer(struct nvnc_display* self, struct nvnc_fb* fb) +{ + if (self->buffer) + nvnc_fb_unref(self->buffer); + + self->buffer = fb; + nvnc_fb_ref(fb); +} + +EXPORT +void nvnc_display_set_render_fn(struct nvnc_display* self, nvnc_render_fn fn) +{ + self->render_fn = fn; +} + +EXPORT +void nvnc_display_damage_region(struct nvnc_display* self, + const struct pixman_region16* region) +{ + // TODO: Shift according to display position + assert(self->server); + nvnc__damage_region(self->server, region); +} + +EXPORT +void nvnc_display_damage_whole(struct nvnc_display* self) +{ + assert(self->server); + + uint16_t width = nvnc_fb_get_width(self->buffer); + uint16_t height = nvnc_fb_get_height(self->buffer); + + struct pixman_region16 damage; + pixman_region_init_rect(&damage, 0, 0, width, height); + nvnc_display_damage_region(self, &damage); + pixman_region_fini(&damage); +} diff --git a/src/server.c b/src/server.c index 368569e..22d0951 100644 --- a/src/server.c +++ b/src/server.c @@ -21,6 +21,7 @@ #include "vec.h" #include "type-macros.h" #include "fb.h" +#include "display.h" #include "neatvnc.h" #include "common.h" #include "pixels.h" @@ -348,18 +349,24 @@ static void disconnect_all_other_clients(struct nvnc_client* client) static void send_server_init_message(struct nvnc_client* client) { struct nvnc* server = client->server; + struct nvnc_display* display = server->display; size_t name_len = strlen(server->name); size_t size = sizeof(struct rfb_server_init_msg) + name_len; - if (!server->buffer) { - log_debug("Tried to send init message, but not buffer has been set\n"); + if (!display) { + log_debug("Tried to send init message, but no display has been added\n"); goto close; } - uint16_t width = nvnc_fb_get_width(server->buffer); - uint16_t height = nvnc_fb_get_height(server->buffer); - uint32_t fourcc = nvnc_fb_get_fourcc_format(server->buffer); + if (!display->buffer) { + log_debug("Tried to send init message, but no framebuffers have been set\n"); + goto close; + } + + uint16_t width = nvnc_fb_get_width(display->buffer); + uint16_t height = nvnc_fb_get_height(display->buffer); + uint32_t fourcc = nvnc_fb_get_fourcc_format(display->buffer); struct rfb_server_init_msg* msg = calloc(1, size); if (!msg) @@ -476,7 +483,7 @@ static int on_client_set_encodings(struct nvnc_client* client) static void process_fb_update_requests(struct nvnc_client* client) { - if (!client->server->buffer) + if (!client->server->display || !client->server->display->buffer) return; if (client->net_stream->state == STREAM_STATE_CLOSED) @@ -829,8 +836,9 @@ void on_main_dispatch(void* aml_obj) return; } - if (self->render_fn) - self->render_fn(self, self->buffer); + struct nvnc_display* display = self->display; + if (display && display->render_fn) + display->render_fn(display, display->buffer); LIST_FOREACH(client, &self->clients, link) process_fb_update_requests(client); @@ -888,8 +896,8 @@ void nvnc_close(struct nvnc* self) { struct nvnc_client* client; - if (self->buffer) - nvnc_fb_unref(self->buffer); + if (self->display) + nvnc_display_unref(self->display); struct nvnc_client* tmp; LIST_FOREACH_SAFE (client, &self->clients, link, tmp) @@ -1006,7 +1014,7 @@ void on_client_update_fb_done(void* work) int schedule_client_update_fb(struct nvnc_client* client) { - struct nvnc_fb* fb = client->server->buffer; + struct nvnc_fb* fb = client->server->display->buffer; assert(fb); DTRACE_PROBE1(neatvnc, update_fb_start, client); @@ -1060,8 +1068,7 @@ pixfmt_failure: return -1; } -EXPORT -void nvnc_damage_region(struct nvnc* self, const struct pixman_region16* damage) +void nvnc__damage_region(struct nvnc* self, const struct pixman_region16* damage) { struct nvnc_client* client; @@ -1071,20 +1078,6 @@ void nvnc_damage_region(struct nvnc* self, const struct pixman_region16* damage) (struct pixman_region16*)damage); } -EXPORT -void nvnc_damage_whole(struct nvnc* self) -{ - assert(self->buffer); - - uint16_t width = nvnc_fb_get_width(self->buffer); - uint16_t height = nvnc_fb_get_height(self->buffer); - - struct pixman_region16 damage; - pixman_region_init_rect(&damage, 0, 0, width, height); - nvnc_damage_region(self, &damage); - pixman_region_fini(&damage); -} - EXPORT void nvnc_set_userdata(void* self, void* userdata) { @@ -1123,12 +1116,6 @@ void nvnc_set_new_client_fn(struct nvnc* self, nvnc_client_fn fn) self->new_client_fn = fn; } -EXPORT -void nvnc_set_render_fn(struct nvnc* self, nvnc_render_fn fn) -{ - self->render_fn = fn; -} - EXPORT void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn) { @@ -1136,17 +1123,30 @@ void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn) } EXPORT -void nvnc_set_buffer(struct nvnc* self, struct nvnc_fb* fb) +void nvnc_add_display(struct nvnc* self, struct nvnc_display* display) { - if (self->buffer) - nvnc_fb_unref(self->buffer); + if (self->display) { + log_error("Multiple displays are not implemented. Aborting!\n"); + abort(); + } - self->buffer = fb; - nvnc_fb_ref(fb); + display->server = self; + self->display = display; + nvnc_display_ref(display); } EXPORT -struct nvnc* nvnc_get_server(const struct nvnc_client* client) +void nvnc_remove_display(struct nvnc* self, struct nvnc_display* display) +{ + if (self->display != display) + return; + + nvnc_display_unref(display); + self->display = NULL; +} + +EXPORT +struct nvnc* nvnc_client_get_server(const struct nvnc_client* client) { return client->server; }