From 2dd32c7adb7116f1ad9ab2632d9fcf57a31e9fa2 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 21 Nov 2011 08:44:10 +0000 Subject: Improve API to allow for RAM surfaces instead of direct blitting Improve and update tests Fix RAM surface Fix VNC surface svn path=/trunk/libnsfb/; revision=13158 --- src/surface/vnc.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 522 insertions(+), 14 deletions(-) (limited to 'src/surface/vnc.c') diff --git a/src/surface/vnc.c b/src/surface/vnc.c index eb6d6ff..eb32560 100644 --- a/src/surface/vnc.c +++ b/src/surface/vnc.c @@ -9,51 +9,559 @@ #include #include +#include +#include + #include "libnsfb.h" #include "libnsfb_event.h" #include "libnsfb_plot.h" + #include "nsfb.h" -#include "frontend.h" +#include "surface.h" +#include "plot.h" +#include "cursor.h" #define UNUSED(x) ((x) = (x)) -static int vnc_set_geometry(nsfb_t *nsfb, int width, int height, int bpp) +static nsfb_event_t *gevent; + +/* vnc special set codes */ +static enum nsfb_key_code_e vnc_nsfb_map[256] = { + NSFB_KEY_UNKNOWN, /* 0x00 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_BACKSPACE, /* 0x08 */ + NSFB_KEY_TAB, + NSFB_KEY_LF, + NSFB_KEY_CLEAR, + NSFB_KEY_UNKNOWN, + NSFB_KEY_RETURN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x10 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_RETURN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x18 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_ESCAPE, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_COMPOSE, /* 0x20 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x28 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x30 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x38 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x40 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x48 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_HOME, /* 0x50 */ + NSFB_KEY_LEFT, + NSFB_KEY_UP, + NSFB_KEY_RIGHT, + NSFB_KEY_DOWN, + NSFB_KEY_PAGEUP, + NSFB_KEY_PAGEDOWN, + NSFB_KEY_END, + NSFB_KEY_HOME, /* 0x58 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x60 */ + NSFB_KEY_PRINT, + NSFB_KEY_HELP, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNDO, + NSFB_KEY_UNKNOWN, + NSFB_KEY_MENU, + NSFB_KEY_UNKNOWN, /* 0x68 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_BREAK, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x70 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x78 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_MODE, + NSFB_KEY_NUMLOCK, + NSFB_KEY_UNKNOWN, /* 0x80 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x88 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_KP_ENTER, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x90 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0x98 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xA0 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xA8 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_KP_MULTIPLY, + NSFB_KEY_KP_PLUS, + NSFB_KEY_UNKNOWN, + NSFB_KEY_KP_MINUS, + NSFB_KEY_KP_PERIOD, + NSFB_KEY_KP_DIVIDE, + NSFB_KEY_KP0, /* 0xB0 */ + NSFB_KEY_KP1, + NSFB_KEY_KP2, + NSFB_KEY_KP3, + NSFB_KEY_KP4, + NSFB_KEY_KP5, + NSFB_KEY_KP6, + NSFB_KEY_KP7, + NSFB_KEY_KP8, /* 0xB8 */ + NSFB_KEY_KP9, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_KP_EQUALS, + NSFB_KEY_F1, + NSFB_KEY_F2, + NSFB_KEY_F3, /* 0xC0 */ + NSFB_KEY_F4, + NSFB_KEY_F5, + NSFB_KEY_F6, + NSFB_KEY_F7, + NSFB_KEY_F8, + NSFB_KEY_F9, + NSFB_KEY_F10, + NSFB_KEY_F11, /* 0xC8 */ + NSFB_KEY_F12, + NSFB_KEY_F13, + NSFB_KEY_F14, + NSFB_KEY_F15, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xD0 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xD8 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xE0 */ + NSFB_KEY_LSHIFT, + NSFB_KEY_RSHIFT, + NSFB_KEY_LCTRL, + NSFB_KEY_RCTRL, + NSFB_KEY_CAPSLOCK, + NSFB_KEY_SCROLLOCK, + NSFB_KEY_LMETA, + NSFB_KEY_RMETA, /* 0xE8 */ + NSFB_KEY_LALT, + NSFB_KEY_RALT, + NSFB_KEY_LSUPER, + NSFB_KEY_RSUPER, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xF0 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, /* 0xF8 */ + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_UNKNOWN, + NSFB_KEY_DELETE, +}; + + +static void vnc_doptr(int buttonMask,int x,int y,rfbClientPtr cl) +{ + static int prevbuttonMask = 0; + + UNUSED(cl); + + if (prevbuttonMask != buttonMask) { + /* button click */ + if (((prevbuttonMask ^ buttonMask) & 0x01) == 0x01) { + if ((buttonMask & 0x01) == 0x01) { + gevent->type = NSFB_EVENT_KEY_DOWN; + } else { + gevent->type = NSFB_EVENT_KEY_UP; + } + gevent->value.keycode = NSFB_KEY_MOUSE_1; + } else if (((prevbuttonMask ^ buttonMask) & 0x02) == 0x02) { + if ((buttonMask & 0x01) == 0x01) { + gevent->type = NSFB_EVENT_KEY_DOWN; + } else { + gevent->type = NSFB_EVENT_KEY_UP; + } + gevent->value.keycode = NSFB_KEY_MOUSE_2; + } else if (((prevbuttonMask ^ buttonMask) & 0x04) == 0x04) { + if ((buttonMask & 0x01) == 0x01) { + gevent->type = NSFB_EVENT_KEY_DOWN; + } else { + gevent->type = NSFB_EVENT_KEY_UP; + } + gevent->value.keycode = NSFB_KEY_MOUSE_3; + } else if (((prevbuttonMask ^ buttonMask) & 0x08) == 0x08) { + if ((buttonMask & 0x01) == 0x01) { + gevent->type = NSFB_EVENT_KEY_DOWN; + } else { + gevent->type = NSFB_EVENT_KEY_UP; + } + gevent->value.keycode = NSFB_KEY_MOUSE_4; + } else if (((prevbuttonMask ^ buttonMask) & 0x10) == 0x10) { + if ((buttonMask & 0x01) == 0x01) { + gevent->type = NSFB_EVENT_KEY_DOWN; + } else { + gevent->type = NSFB_EVENT_KEY_UP; + } + gevent->value.keycode = NSFB_KEY_MOUSE_5; + } + prevbuttonMask = buttonMask; + } else { + gevent->type = NSFB_EVENT_MOVE_ABSOLUTE; + gevent->value.vector.x = x; + gevent->value.vector.y = y; + gevent->value.vector.z = 0; + } + +} + + +static void vnc_dokey(rfbBool down, rfbKeySym key, rfbClientPtr cl) +{ + enum nsfb_key_code_e keycode = NSFB_KEY_UNKNOWN; + + UNUSED(cl); + + if ((key >= XK_space) && (key <= XK_asciitilde)) { + /* ascii codes line up */ + keycode = key; + } else if ((key & 0xff00) == 0xff00) { + /* bottom 8bits of keysyms in this range map via table */ + keycode = vnc_nsfb_map[(key & 0xff)]; + } + + if (down == 0) { + /* key up */ + gevent->type = NSFB_EVENT_KEY_UP; + } else { + /* key down */ + gevent->type = NSFB_EVENT_KEY_DOWN; + } + gevent->value.keycode = keycode; + +} + + +static int vnc_set_geometry(nsfb_t *nsfb, int width, int height, enum nsfb_format_e format) { - if (nsfb->frontend_priv != NULL) - return -1; /* if were already initialised fail */ + if (nsfb->surface_priv != NULL) + return -1; /* fail if surface already initialised */ + + if (width > 0) { + nsfb->width = width; + } + + if (height > 0) { + nsfb->height = height; + } + + if (format != NSFB_FMT_ANY) { + nsfb->format = format; + } - nsfb->width = width; - nsfb->height = height; - nsfb->bpp = bpp; + /* select soft plotters appropriate for format */ + select_plotters(nsfb); return 0; } static int vnc_initialise(nsfb_t *nsfb) { - UNUSED(nsfb); + rfbScreenInfoPtr vncscreen; + int argc = 0; + char **argv = NULL; + + if (nsfb->surface_priv != NULL) + return -1; /* fail if surface already initialised */ + + /* sanity checked depth. */ + if (nsfb->bpp != 32) + return -1; + + /* create vnc screen with 8bits per sample, three samples per + * pixel and 4 bytes per pixel. */ + vncscreen = rfbGetScreen(&argc, argv, + nsfb->width, nsfb->height, + 8, 3, (nsfb->bpp / 8)); + + if (vncscreen == NULL) { + /* Note libvncserver does not check its own allocations/error + * paths so the faliure mode of the rfbGetScreen is to segfault. + */ + return -1; + } + + vncscreen->frameBuffer = malloc(nsfb->width * nsfb->height * (nsfb->bpp / 8)); + + if (vncscreen->frameBuffer == NULL) { + rfbScreenCleanup(vncscreen); + return -1; + } + + + switch (nsfb->bpp) { + case 8: + break; + + case 16: + vncscreen->serverFormat.trueColour=TRUE; + vncscreen->serverFormat.redShift = 11; + vncscreen->serverFormat.greenShift = 5; + vncscreen->serverFormat.blueShift = 0; + vncscreen->serverFormat.redMax = 31; + vncscreen->serverFormat.greenMax = 63; + vncscreen->serverFormat.blueMax = 31; + break; + + case 32: + vncscreen->serverFormat.trueColour=TRUE; + vncscreen->serverFormat.redShift = 16; + vncscreen->serverFormat.greenShift = 8; + vncscreen->serverFormat.blueShift = 0; + break; + } + + vncscreen->alwaysShared = TRUE; + vncscreen->autoPort = 1; + vncscreen->ptrAddEvent = vnc_doptr; + vncscreen->kbdAddEvent = vnc_dokey; + + rfbInitServer(vncscreen); + + /* keep parameters */ + nsfb->surface_priv = vncscreen; + nsfb->ptr = (uint8_t *)vncscreen->frameBuffer; + nsfb->linelen = (nsfb->width * nsfb->bpp) / 8; + return 0; } static int vnc_finalise(nsfb_t *nsfb) { - UNUSED(nsfb); + rfbScreenInfoPtr vncscreen = nsfb->surface_priv; + + if (vncscreen != NULL) { + rfbScreenCleanup(vncscreen); + } + + return 0; +} + + +static int vnc_update(nsfb_t *nsfb, nsfb_bbox_t *box) +{ + rfbScreenInfoPtr vncscreen = nsfb->surface_priv; + + rfbMarkRectAsModified(vncscreen, box->x0, box->y0, box->x1, box->y1); + return 0; } + static bool vnc_input(nsfb_t *nsfb, nsfb_event_t *event, int timeout) { - UNUSED(nsfb); - UNUSED(event); - UNUSED(timeout); + rfbScreenInfoPtr vncscreen = nsfb->surface_priv; + int ret; + + if (vncscreen != NULL) { + + gevent = event; /* blergh - have to use global state to pass data */ + + /* set default to timeout */ + event->type = NSFB_EVENT_CONTROL; + event->value.controlcode = NSFB_CONTROL_TIMEOUT; + + ret = rfbProcessEvents(vncscreen, timeout * 1000); + return true; + } + return false; } -const nsfb_frontend_rtns_t vnc_rtns = { +static int +vnc_cursor(nsfb_t *nsfb, struct nsfb_cursor_s *cursor) +{ + rfbScreenInfoPtr vncscreen = nsfb->surface_priv; + rfbCursorPtr vnccursor = calloc(1,sizeof(rfbCursor)); + int rwidth; /* rounded width */ + int row; + int col; + const nsfb_colour_t *pixel; + uint8_t bit; + + rwidth = (cursor->bmp_width + 7) / 8; + + vnccursor->cleanup = 1; /* rfb lib will free this allocation */ + vnccursor->width = cursor->bmp_width; + vnccursor->height = cursor->bmp_height; + vnccursor->foreRed = vnccursor->foreGreen = vnccursor->foreBlue = 0xffff; + + vnccursor->source = calloc(rwidth, vnccursor->height); + vnccursor->cleanupSource = 1; /* rfb lib will free this allocation */ + vnccursor->mask = calloc(rwidth, vnccursor->height); + vnccursor->cleanupMask = 1; /* rfb lib will free this allocation */ + + for (row = 0, pixel = cursor->pixel; row < vnccursor->height; row++) { + for (col = 0, bit = 0x80; + col < vnccursor->width; + col++, bit = (bit & 1)? 0x80 : bit>>1, pixel++) { + + /* pixel luminance more than 50% */ + if ((((((*pixel) & 0xff) * 77) + + ((((*pixel) & 0xff00) >> 8) * 151) + + ((((*pixel) & 0xff0000) >> 16) * 28)) / 256) > 128) { + + vnccursor->source[row * rwidth + col/8] |= bit; + } + if (((*pixel) & 0xff000000) != 0) { + vnccursor->mask[row * rwidth + col/8] |= bit; + } + } + } + + rfbSetCursor(vncscreen, vnccursor); + return true; +} + +const nsfb_surface_rtns_t vnc_rtns = { .initialise = vnc_initialise, .finalise = vnc_finalise, .input = vnc_input, + .update = vnc_update, + .cursor = vnc_cursor, .geometry = vnc_set_geometry, }; -NSFB_FRONTEND_DEF(vnc, NSFB_FRONTEND_VNC, &vnc_rtns) +NSFB_SURFACE_DEF(vnc, NSFB_SURFACE_VNC, &vnc_rtns) + +/* + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * End: + */ -- cgit v1.2.3