mirror of
https://github.com/TobleMiner/shoreline.git
synced 2025-02-22 14:53:58 +01:00
173 lines
4.3 KiB
C
173 lines
4.3 KiB
C
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
#include "main.h"
|
|
#include "vnc.h"
|
|
#include "framebuffer.h"
|
|
|
|
static const struct frontend_ops fops = {
|
|
.alloc = vnc_alloc,
|
|
.start = vnc_start,
|
|
.free = vnc_free,
|
|
.update = vnc_update,
|
|
.draw_string = vnc_draw_string,
|
|
};
|
|
|
|
static const struct frontend_arg fargs[] = {
|
|
{ .name = "port", .configure = vnc_configure_port },
|
|
{ .name = "font", .configure = vnc_configure_font },
|
|
{ .name = "flickerfree", .configure = vnc_configure_flicker },
|
|
{ .name = "", .configure = NULL },
|
|
};
|
|
|
|
DECLARE_FRONTEND_SIG_ARGS(front_vnc, "VNC server frontend", &fops, fargs);
|
|
|
|
static void set_shared(struct vnc* vnc, bool shared) {
|
|
vnc->server->alwaysShared = shared ? TRUE : FALSE;
|
|
vnc->server->neverShared = shared ? FALSE : TRUE;
|
|
}
|
|
|
|
static void pre_display_cb(struct _rfbClientRec* client) {
|
|
struct vnc* vnc = client->screen->screenData;
|
|
if(vnc->front.sync_overlay_draw) {
|
|
pthread_mutex_lock(&vnc->draw_lock);
|
|
draw_overlays(vnc->fb_overlay);
|
|
}
|
|
}
|
|
|
|
static void post_display_cb(struct _rfbClientRec* client, int result) {
|
|
struct vnc* vnc = client->screen->screenData;
|
|
if(vnc->front.sync_overlay_draw) {
|
|
pthread_mutex_unlock(&vnc->draw_lock);
|
|
}
|
|
}
|
|
|
|
int vnc_alloc(struct frontend** ret, struct fb* fb, void* priv) {
|
|
int err = 0;
|
|
struct vnc* vnc = calloc(1, sizeof(struct vnc));
|
|
struct fb_size* size;
|
|
if(!vnc) {
|
|
err = -ENOMEM;
|
|
goto fail;
|
|
}
|
|
|
|
pthread_mutex_init(&vnc->draw_lock, NULL);
|
|
vnc->fb = fb;
|
|
size = fb_get_size(fb);
|
|
|
|
if((err = fb_alloc(&vnc->fb_overlay, size->width, size->height))) {
|
|
goto fail_vnc;
|
|
}
|
|
|
|
vnc->server = rfbGetScreen(NULL, NULL, size->width, size->height, 8, 3, 4);
|
|
if(!vnc->server) {
|
|
err = -ENOMEM;
|
|
goto fail_fb;
|
|
}
|
|
|
|
vnc->server->bitsPerPixel = 32;
|
|
vnc->server->depth = 24;
|
|
rfbPixelFormat* format = &vnc->server->serverFormat;
|
|
format->depth = 24;
|
|
format->redMax = 0xFF;
|
|
format->greenMax = 0xFF;
|
|
format->blueMax = 0xFF;
|
|
format->redShift = 24;
|
|
format->greenShift = 16;
|
|
format->blueShift = 8;
|
|
|
|
vnc->server->displayHook = pre_display_cb;
|
|
vnc->server->displayFinishedHook = post_display_cb;
|
|
vnc->server->screenData = vnc;
|
|
vnc->server->frameBuffer = (char *)vnc->fb_overlay->pixels;
|
|
vnc->server->desktopName = "shoreline";
|
|
set_shared(vnc, true);
|
|
|
|
*ret = &vnc->front;
|
|
|
|
return 0;
|
|
|
|
fail_fb:
|
|
fb_free(vnc->fb_overlay);
|
|
fail_vnc:
|
|
free(vnc);
|
|
fail:
|
|
return err;
|
|
};
|
|
|
|
int vnc_start(struct frontend* front) {
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
rfbInitServer(vnc->server);
|
|
rfbRunEventLoop(vnc->server, -1, TRUE);
|
|
return 0;
|
|
}
|
|
|
|
void vnc_free(struct frontend* front) {
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
rfbShutdownServer(vnc->server, TRUE);
|
|
rfbScreenCleanup(vnc->server);
|
|
free(vnc);
|
|
}
|
|
|
|
int vnc_update(struct frontend* front) {
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
if(front->sync_overlay_draw) {
|
|
pthread_mutex_lock(&vnc->draw_lock);
|
|
}
|
|
fb_copy(vnc->fb_overlay, vnc->fb);
|
|
if(front->sync_overlay_draw) {
|
|
pthread_mutex_unlock(&vnc->draw_lock);
|
|
}
|
|
rfbMarkRectAsModified(vnc->server, 0, 0, vnc->fb->size.width, vnc->fb->size.height);
|
|
return !rfbIsActive(vnc->server);
|
|
}
|
|
|
|
int vnc_draw_string(struct frontend* front, unsigned x, unsigned y, char* str) {
|
|
int space, width;
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
if(vnc->font) {
|
|
space = rfbWidthOfString(vnc->font, " ");
|
|
width = rfbWidthOfString(vnc->font, str);
|
|
rfbFillRect(vnc->server, x, y, x + width + 2 * space, y + VNC_FONT_HEIGHT + 4, 0x00000000);
|
|
rfbDrawString(vnc->server, vnc->font, x + space, y + VNC_FONT_HEIGHT + 2, str, 0xffffffff);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int vnc_configure_port(struct frontend* front, char* value) {
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
if(!value) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
int port = atoi(value);
|
|
if(port < 0 || port > 65535) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
vnc->server->port = vnc->server->ipv6port = port;
|
|
vnc->server->autoPort = FALSE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int vnc_configure_font(struct frontend* front, char* value) {
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
if(!value) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
vnc->font = rfbLoadConsoleFont(value);
|
|
if(!vnc->font) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int vnc_configure_flicker(struct frontend* front, char* value) {
|
|
struct vnc* vnc = container_of(front, struct vnc, front);
|
|
front->sync_overlay_draw = true;
|
|
set_shared(vnc, false);
|
|
return 0;
|
|
}
|