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.
pull/30/head
Andri Yngvason 2020-04-12 18:16:19 +00:00
parent 737dd311a0
commit f3e09fd622
8 changed files with 228 additions and 59 deletions

View File

@ -35,6 +35,7 @@ struct coord {
}; };
struct draw { struct draw {
struct nvnc_display* display;
struct nvnc_fb* fb; struct nvnc_fb* fb;
struct coord coord[MAX_COORD]; struct coord coord[MAX_COORD];
int index; int index;
@ -47,8 +48,8 @@ int coord_distance_between(struct coord a, struct coord b)
return round(sqrt(x * x + y * y)); return round(sqrt(x * x + y * y));
} }
void draw_dot(struct nvnc* nvnc, struct nvnc_fb* fb, struct coord coord, void draw_dot(struct nvnc_display* display, struct nvnc_fb* fb,
int radius, uint32_t colour) struct coord coord, int radius, uint32_t colour)
{ {
uint32_t* image = nvnc_fb_get_addr(fb); uint32_t* image = nvnc_fb_get_addr(fb);
int width = nvnc_fb_get_width(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; struct pixman_region16 region;
pixman_region_init_rect(&region, start.x, start.y, pixman_region_init_rect(&region, start.x, start.y,
stop.x - start.x, stop.y - start.y); stop.x - start.x, stop.y - start.y);
nvnc_damage_region(nvnc, &region); nvnc_display_damage_region(display, &region);
pixman_region_fini(&region); pixman_region_fini(&region);
/* The brute force method. ;) */ /* 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)) if (!(buttons & NVNC_BUTTON_LEFT))
return; return;
struct nvnc* server = nvnc_get_server(client); struct nvnc* server = nvnc_client_get_server(client);
assert(server); assert(server);
struct draw* draw = nvnc_get_userdata(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; struct pixman_region16 region;
pixman_region_init_rect(&region, 0, 0, width, height); pixman_region_init_rect(&region, 0, 0, width, height);
pixman_region_intersect_rect(&region, &region, x, y, 1, 1); pixman_region_intersect_rect(&region, &region, x, y, 1, 1);
nvnc_damage_region(server, &region); nvnc_display_damage_region(draw->display, &region);
pixman_region_fini(&region); pixman_region_fini(&region);
} }
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); struct draw* draw = nvnc_get_userdata(server);
assert(draw); assert(draw);
for (int i = 0; i < draw->index; ++i) 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; draw->index = 0;
} }
@ -138,12 +142,18 @@ int main(int argc, char* argv[])
aml_set_default(aml); aml_set_default(aml);
struct nvnc* server = nvnc_open("127.0.0.1", 5900); 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_name(server, "Draw");
nvnc_set_pointer_fn(server, on_pointer_event); nvnc_set_pointer_fn(server, on_pointer_event);
nvnc_set_userdata(server, &draw); 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); struct aml_signal* sig = aml_signal_new(SIGINT, on_sigint, NULL, NULL);
aml_start(aml_get_default(), sig); aml_start(aml_get_default(), sig);
@ -152,6 +162,7 @@ int main(int argc, char* argv[])
aml_run(aml); aml_run(aml);
nvnc_close(server); nvnc_close(server);
nvnc_display_unref(draw.display);
nvnc_fb_unref(draw.fb); nvnc_fb_unref(draw.fb);
aml_unref(aml); aml_unref(aml);
} }

View File

@ -48,11 +48,17 @@ int main(int argc, char* argv[])
aml_set_default(aml); aml_set_default(aml);
struct nvnc* server = nvnc_open("127.0.0.1", 5900); 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_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); struct aml_signal* sig = aml_signal_new(SIGINT, on_sigint, NULL, NULL);
aml_start(aml_get_default(), sig); aml_start(aml_get_default(), sig);
@ -61,6 +67,7 @@ int main(int argc, char* argv[])
aml_run(aml); aml_run(aml);
nvnc_close(server); nvnc_close(server);
nvnc_display_unref(display);
nvnc_fb_unref(fb); nvnc_fb_unref(fb);
aml_unref(aml); aml_unref(aml);
} }

View File

@ -52,6 +52,7 @@ struct nvnc;
struct stream; struct stream;
struct aml_handler; struct aml_handler;
struct aml_idle; struct aml_idle;
struct nvnc_display;
struct nvnc_common { struct nvnc_common {
void* userdata; void* userdata;
@ -93,8 +94,7 @@ struct nvnc {
nvnc_pointer_fn pointer_fn; nvnc_pointer_fn pointer_fn;
nvnc_fb_req_fn fb_req_fn; nvnc_fb_req_fn fb_req_fn;
nvnc_client_fn new_client_fn; nvnc_client_fn new_client_fn;
nvnc_render_fn render_fn; struct nvnc_display* display;
struct nvnc_fb* buffer;
#ifdef ENABLE_TLS #ifdef ENABLE_TLS
gnutls_certificate_credentials_t tls_creds; gnutls_certificate_credentials_t tls_creds;
@ -102,3 +102,6 @@ struct nvnc {
void* auth_ud; void* auth_ud;
#endif #endif
}; };
void nvnc__damage_region(struct nvnc* self,
const struct pixman_region16* damage);

33
include/display.h 100644
View File

@ -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 <stdint.h>
#include <pixels.h>
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;
};

View File

@ -21,6 +21,7 @@
struct nvnc; struct nvnc;
struct nvnc_client; struct nvnc_client;
struct nvnc_display;
struct nvnc_fb; struct nvnc_fb;
struct pixman_region16; 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 void (*nvnc_damage_fn)(struct pixman_region16* damage, void* userdata);
typedef bool (*nvnc_auth_fn)(const char* username, const char* password, typedef bool (*nvnc_auth_fn)(const char* username, const char* password,
void* userdata); 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); struct nvnc* nvnc_open(const char* addr, uint16_t port);
void nvnc_close(struct nvnc* self); 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_set_userdata(void* self, void* userdata);
void* nvnc_get_userdata(const void* self); void* nvnc_get_userdata(const void* self);
struct nvnc* nvnc_get_server(const struct nvnc_client* client); struct nvnc* nvnc_client_get_server(const struct nvnc_client* client);
void nvnc_set_buffer(struct nvnc*, struct nvnc_fb*);
void nvnc_set_name(struct nvnc* self, const char* name); 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_pointer_fn(struct nvnc* self, nvnc_pointer_fn);
void nvnc_set_fb_req_fn(struct nvnc* self, nvnc_fb_req_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_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); void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn);
bool nvnc_has_auth(void); 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); uint16_t nvnc_fb_get_height(const struct nvnc_fb* fb);
uint32_t nvnc_fb_get_fourcc_format(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); struct nvnc_display* nvnc_display_new(uint16_t x_pos, uint16_t y_pos);
void nvnc_damage_whole(struct nvnc*); 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 * Find the regions that differ between fb0 and fb1. Regions outside the hinted

View File

@ -58,6 +58,7 @@ sources = [
'src/fb.c', 'src/fb.c',
'src/rcbuf.c', 'src/rcbuf.c',
'src/stream.c', 'src/stream.c',
'src/display.c',
] ]
dependencies = [ dependencies = [

103
src/display.c 100644
View File

@ -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 <assert.h>
#include <stdlib.h>
#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);
}

View File

@ -21,6 +21,7 @@
#include "vec.h" #include "vec.h"
#include "type-macros.h" #include "type-macros.h"
#include "fb.h" #include "fb.h"
#include "display.h"
#include "neatvnc.h" #include "neatvnc.h"
#include "common.h" #include "common.h"
#include "pixels.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) static void send_server_init_message(struct nvnc_client* client)
{ {
struct nvnc* server = client->server; struct nvnc* server = client->server;
struct nvnc_display* display = server->display;
size_t name_len = strlen(server->name); size_t name_len = strlen(server->name);
size_t size = sizeof(struct rfb_server_init_msg) + name_len; size_t size = sizeof(struct rfb_server_init_msg) + name_len;
if (!server->buffer) { if (!display) {
log_debug("Tried to send init message, but not buffer has been set\n"); log_debug("Tried to send init message, but no display has been added\n");
goto close; goto close;
} }
uint16_t width = nvnc_fb_get_width(server->buffer); if (!display->buffer) {
uint16_t height = nvnc_fb_get_height(server->buffer); log_debug("Tried to send init message, but no framebuffers have been set\n");
uint32_t fourcc = nvnc_fb_get_fourcc_format(server->buffer); 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); struct rfb_server_init_msg* msg = calloc(1, size);
if (!msg) 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) static void process_fb_update_requests(struct nvnc_client* client)
{ {
if (!client->server->buffer) if (!client->server->display || !client->server->display->buffer)
return; return;
if (client->net_stream->state == STREAM_STATE_CLOSED) if (client->net_stream->state == STREAM_STATE_CLOSED)
@ -829,8 +836,9 @@ void on_main_dispatch(void* aml_obj)
return; return;
} }
if (self->render_fn) struct nvnc_display* display = self->display;
self->render_fn(self, self->buffer); if (display && display->render_fn)
display->render_fn(display, display->buffer);
LIST_FOREACH(client, &self->clients, link) LIST_FOREACH(client, &self->clients, link)
process_fb_update_requests(client); process_fb_update_requests(client);
@ -888,8 +896,8 @@ void nvnc_close(struct nvnc* self)
{ {
struct nvnc_client* client; struct nvnc_client* client;
if (self->buffer) if (self->display)
nvnc_fb_unref(self->buffer); nvnc_display_unref(self->display);
struct nvnc_client* tmp; struct nvnc_client* tmp;
LIST_FOREACH_SAFE (client, &self->clients, link, 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) 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); assert(fb);
DTRACE_PROBE1(neatvnc, update_fb_start, client); DTRACE_PROBE1(neatvnc, update_fb_start, client);
@ -1060,8 +1068,7 @@ pixfmt_failure:
return -1; 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; struct nvnc_client* client;
@ -1071,20 +1078,6 @@ void nvnc_damage_region(struct nvnc* self, const struct pixman_region16* damage)
(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 EXPORT
void nvnc_set_userdata(void* self, void* userdata) 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; self->new_client_fn = fn;
} }
EXPORT
void nvnc_set_render_fn(struct nvnc* self, nvnc_render_fn fn)
{
self->render_fn = fn;
}
EXPORT EXPORT
void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn) 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 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) if (self->display) {
nvnc_fb_unref(self->buffer); log_error("Multiple displays are not implemented. Aborting!\n");
abort();
}
self->buffer = fb; display->server = self;
nvnc_fb_ref(fb); self->display = display;
nvnc_display_ref(display);
} }
EXPORT 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; return client->server;
} }