From 181cec4348da40331b3e8ab365732c025ec149b2 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Wed, 27 Apr 2011 19:24:15 +0200 Subject: Import upstream version 0.11.0~svn1143 --- drv_vnc.c | 547 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 547 insertions(+) create mode 100644 drv_vnc.c (limited to 'drv_vnc.c') diff --git a/drv_vnc.c b/drv_vnc.c new file mode 100644 index 0000000..5249206 --- /dev/null +++ b/drv_vnc.c @@ -0,0 +1,547 @@ +/* $Id: drv_vnc.c 1031 2009-04-15 21:34:51Z michux $ + * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_vnc.c $ + * + * Libvncserver driver + * + * Copyright (C) 2009 Michael Vogt + * Modified from sample code by: + * Copyright (C) 2005 Michael Reinelt + * Copyright (C) 2005, 2006, 2007, 2008, 2009 The LCD4Linux Team + * + * This file is part of LCD4Linux. + * + * LCD4Linux is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LCD4Linux is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * + * exported fuctions: + * + * struct DRIVER drv_vnc + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +/* struct timeval */ +#include + +#include "debug.h" +#include "cfg.h" +#include "qprintf.h" +#include "udelay.h" +#include "plugin.h" +#include "widget.h" +#include "widget_text.h" +#include "widget_icon.h" +#include "widget_bar.h" +#include "widget_keypad.h" +#include "drv.h" +#include "drv_generic_graphic.h" +#include "drv_generic_keypad.h" + +//todo: key widget text + +#define NO_MOUSE_BUTTON_PRESSED 0 +#define LEFT_MOUSE_BUTTON_PRESSED 1 +#define SLEEP_STEPS 1000 + +static char Name[] = "VNC"; + +static int xres = 320; /* screen settings */ +static int yres = 200; +static int BPP = 4; +static int max_clients = 2; /* max connected clients */ +static int osd_showtime = 2000; /* time to display the osd in ms */ +static int buttons = 2; /* number of keypad buttons */ +static int buttonsize = 50; /* size of keypad buttons */ +static int keypadxofs = 0; +static int keypadyofs = 0; +static int keypadgap = 0; +static int port = 5900; +static int httpPort = 5800; +static unsigned char framer = 0; +static unsigned char frameg = 0; +static unsigned char frameb = 0; + +static rfbScreenInfoPtr server; /* vnc device */ +static struct timeval osd_timestamp; +static int show_keypad_osd = 0; /* is the osd active? */ +static int clientCount = 0; /* currently connected clients */ +static int mouse_x = 0; +static int mouse_y = 0; +static int mouse_stat_old = 0; +static int process_event = 0; +static long frames = 0; +static char *password; +static char *javaClassFiles; +static struct timeval startDriver; +static int maxfps = -1; + +/* draws a simple rect, used to display keypad */ +int draw_rect(int x, int y, int size, unsigned char col, char *buffer) +{ + int ofs, ofs2, i, ret; + unsigned char colr, colg; + colr = colg = col; + ret = 0; + + /* check if mouse is in current rect */ + if (mouse_x > x && mouse_x < (x + size)) + if (mouse_y > y && mouse_y < (y + size)) { + colr = framer; + colg = frameg; + col = frameb; + ret = 1; + } + + ofs2 = size * xres * BPP; + for (i = x; i < x + size; i++) { + ofs = (i + xres * y) * BPP; + buffer[ofs + ofs2] = colr; + buffer[ofs++] = colr; + buffer[ofs + ofs2] = colg; + buffer[ofs++] = colg; + buffer[ofs + ofs2] = col; + buffer[ofs++] = col; + } + + ofs2 = size * BPP; + for (i = y; i <= y + size; i++) { + ofs = (i * xres + x) * BPP; + buffer[ofs + ofs2] = colr; + buffer[ofs++] = colr; + buffer[ofs + ofs2] = colg; + buffer[ofs++] = colg; + buffer[ofs + ofs2] = col; + buffer[ofs++] = col; + } + return ret; +} + +void display_keypad() +{ + int i, rectx, recty; + int active; + for (i = 0; i < buttons; i++) { + rectx = keypadxofs + (i * (buttonsize + keypadgap)); + recty = keypadyofs /*+ (i*(buttonsize+gap)) */ ; + active = draw_rect(rectx, recty, buttonsize, 0, server->frameBuffer); + + /* if the lmb button is pressed and we didnt processed the event yet - do it now */ + if (active == 1 && process_event == 1) { + drv_generic_keypad_press(i + 1); + //debug("mouse in keypad nr %d", i); + process_event = 0; + } + } +} + +/* called if a vnc client disconnects */ +static void clientgone( __attribute__ ((unused)) rfbClientPtr cl) +{ + if (clientCount > 0) + clientCount--; + debug("%d clients connected", clientCount); +} + +/* called if a vnc client connect */ +static enum rfbNewClientAction hook_newclient(rfbClientPtr cl) +{ + if (clientCount < max_clients) { + clientCount++; + cl->clientGoneHook = clientgone; + debug("%d clients connected", clientCount); + return RFB_CLIENT_ACCEPT; + } else { + info("client refused due max. client connections (%d)", clientCount); + return RFB_CLIENT_REFUSE; + } +} + +/* handle mouse action */ +static void hook_mouseaction(int buttonMask, int x, int y, rfbClientPtr cl) +{ + if (x >= 0 && y >= 0 && x < xres && y < yres) { + process_event = 0; + + /* process ONLY if mouse button is released. */ + if (buttonMask == NO_MOUSE_BUTTON_PRESSED && mouse_stat_old == LEFT_MOUSE_BUTTON_PRESSED) { + gettimeofday(&osd_timestamp, NULL); + process_event = 1; + mouse_x = x; + mouse_y = y; + } + //debug("btnMask: %d, old state: %d, processevent: %d", buttonMask, mouse_stat_old, process_event); + + /* show osd display if mouse is pressed */ + if (buttonMask == 1) { + gettimeofday(&osd_timestamp, NULL); + mouse_x = x; + mouse_y = y; + if (show_keypad_osd == 0) { + /* no osd until yet, activate osd keypad ... */ + show_keypad_osd = 1; + } + } + + } + + mouse_stat_old = buttonMask; + rfbDefaultPtrAddEvent(buttonMask, x, y, cl); +} + +static int drv_vnc_keypad(const int num) +{ + int val = WIDGET_KEY_PRESSED; + + switch (num) { + case 1: + val += WIDGET_KEY_UP; + break; + case 2: + val += WIDGET_KEY_DOWN; + break; + case 3: + val += WIDGET_KEY_LEFT; + break; + case 4: + val += WIDGET_KEY_RIGHT; + break; + case 5: + val += WIDGET_KEY_CONFIRM; + break; + case 6: + val += WIDGET_KEY_CANCEL; + break; + default: + error("%s: unknown keypad value %d", Name, num); + } + + return val; +} + +/* init the driver, read config */ +static int drv_vnc_open(const char *Section) +{ + int keypadcol; + if (cfg_number(Section, "Xres", 320, 32, 2048, &xres) < 1) { + info("[DRV_VNC] no '%s.Xres' entry from %s using default %d", Section, cfg_source(), xres); + } + if (cfg_number(Section, "Yres", 200, 32, 2048, &yres) < 1) { + info("[DRV_VNC] no '%s.Yres' entry from %s using default %d", Section, cfg_source(), yres); + } + if (cfg_number(Section, "Bpp", 4, 1, 4, &BPP) < 1) { + info("[DRV_VNC] no '%s.Bpp' entry from %s using default %d", Section, cfg_source(), BPP); + } + if (cfg_number(Section, "Maxclients", 2, 1, 64, &max_clients) < 1) { + info("[DRV_VNC] no '%s.Maxclients' entry from %s using default %d", Section, cfg_source(), max_clients); + } + if (cfg_number(Section, "Osd_showtime", 2000, 500, 60000, &osd_showtime) < 1) { + info("[DRV_VNC] no '%s.Osd_showtime' entry from %s using default %d", Section, cfg_source(), osd_showtime); + } + if (cfg_number(Section, "Buttons", 2, 0, 6, &buttons) < 1) { + info("[DRV_VNC] no '%s.Buttons' entry from %s using default %d", Section, cfg_source(), buttons); + } + if (cfg_number(Section, "Buttonsize", 50, 8, 256, &buttonsize) < 1) { + info("[DRV_VNC] no '%s.Buttonsize' entry from %s using default %d", Section, cfg_source(), buttonsize); + } + if (cfg_number(Section, "Keypadxofs", 0, 0, 4096, &keypadxofs) < 1) { + info("[DRV_VNC] no '%s.Keypadxofs' entry from %s using default %d", Section, cfg_source(), keypadxofs); + } + if (cfg_number(Section, "Keypadyofs", 0, 0, 4096, &keypadyofs) < 1) { + info("[DRV_VNC] no '%s.Keypadyofs' entry from %s using default %d", Section, cfg_source(), keypadyofs); + } + if (cfg_number(Section, "Keypadgap", 10, 0, 2048, &keypadgap) < 1) { + info("[DRV_VNC] no '%s.Keypadgap' entry from %s using default %d", Section, cfg_source(), keypadgap); + } + if (cfg_number(Section, "Keypadcol", 255, 0, 0xffffff, &keypadcol) < 1) { + info("[DRV_VNC] no '%s.Keypadcol' entry from %s using default red", Section, cfg_source()); + framer = 255; + } else { + framer = keypadcol & 0xff; + frameg = (keypadcol & 0xff00) >> 8; + frameb = (keypadcol & 0xff0000) >> 16; + } + if (cfg_number(Section, "Port", 5900, 1, 65535, &port) < 1) { + info("[DRV_VNC] no '%s.Port' entry from %s using default %d", Section, cfg_source(), port); + } + if (cfg_number(Section, "HttpPort", 5800, 1, 65535, &httpPort) < 1) { + info("[DRV_VNC] no '%s.HttpPort' entry from %s using default %d", Section, cfg_source(), httpPort); + } + if (cfg_number(Section, "Maxfps", -1, -1, 512, &maxfps) < 1) { + info("[DRV_VNC] no '%s.Maxfps' entry from %s using default %d", Section, cfg_source(), maxfps); + } + password = cfg_get(Section, "Password", NULL); + if (password != NULL) { + info("[DRV_VNC] password enabled"); + } + javaClassFiles = cfg_get(Section, "HttpDir", NULL); + if (javaClassFiles != NULL) { + info("[DRV_VNC] HTTP server enabled"); + } + return 0; +} + +/* shutdown driver, release allocated stuff */ +static int drv_vnc_close(void) +{ + rfbShutdownServer(server, TRUE); + free(server->frameBuffer); + return 0; +} + + +/* actual blitting method */ +static void drv_vnc_blit_it(const int row, const int col, const int height, const int width, unsigned char *buffer) +{ + static int sleep = 0; + int r, c, ofs; + RGBA p; + + for (r = row; r < row + height; r++) { + for (c = col; c < col + width; c++) { + p = drv_generic_graphic_rgb(r, c); + ofs = (r * xres + c) * BPP; + buffer[ofs++] = p.R; + buffer[ofs++] = p.G; + buffer[ofs++] = p.B; + buffer[ofs] = 255; + } + } + + /* display osd keypad */ + if (show_keypad_osd == 1) { + display_keypad(); + + /* check if the osd should be disabled after the waittime */ + struct timeval now; + gettimeofday(&now, NULL); + int timedelta = (now.tv_sec - osd_timestamp.tv_sec) * 1000 + (now.tv_usec - osd_timestamp.tv_usec) / 1000; + + if (timedelta > osd_showtime) { + show_keypad_osd = 0; + } + } + frames++; + if ((frames % 10) == 0 && maxfps > 0) { + struct timeval blittime; + gettimeofday(&blittime, NULL); + int time_since_start = + (blittime.tv_sec - startDriver.tv_sec) * 1000 + (blittime.tv_usec - startDriver.tv_usec) / 1000; + + /* if time changed since start of lcd4linux */ + if (time_since_start < 0) { + gettimeofday(&startDriver, NULL); + time_since_start = + (blittime.tv_sec - startDriver.tv_sec) * 1000 + (blittime.tv_usec - startDriver.tv_usec) / 1000; + if (time_since_start == 0) + time_since_start = 1; + } + //info("time :%d, frames: %d, sleep: %d", time_since_start, frames, sleep); + + int fps = (int) (1000 * frames / time_since_start); + + if (fps > maxfps) { + sleep += SLEEP_STEPS; + } + + if (fps < maxfps && sleep >= SLEEP_STEPS) { + sleep -= SLEEP_STEPS; + } + } + usleep(sleep); + +} + + +static void drv_vnc_blit(const int row, const int col, const int height, const int width) +{ + + if (rfbIsActive(server)) { + drv_vnc_blit_it(row, col, height, width, (unsigned char *) server->frameBuffer); + + if (clientCount > 0) { + rfbMarkRectAsModified(server, 0, 0, xres, yres); + } + rfbProcessEvents(server, server->deferUpdateTime * 500); + } +} + +/* start graphic display */ +static int drv_vnc_start(const char *section) +{ + char *s; + + s = cfg_get(section, "Font", "6x8"); + if (s == NULL || *s == '\0') { + error("%s: no '%s.Font' entry from %s", Name, section, cfg_source()); + return -1; + } + + XRES = -1; + YRES = -1; + if (sscanf(s, "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) { + error("%s: bad Font '%s' from %s", Name, s, cfg_source()); + return -1; + } + + /* Fixme: provider other fonts someday... */ + if (XRES != 6 && YRES != 8) { + error("%s: bad Font '%s' from %s (only 6x8 at the moment)", Name, s, cfg_source()); + return -1; + } + + /* open communication with the display */ + if (drv_vnc_open(section) < 0) { + return -1; + } + + /* you surely want to allocate a framebuffer or something... */ + server = rfbGetScreen(0, NULL, xres, yres, 8, 3, BPP); + server->desktopName = "LCD4Linux VNC Driver"; + server->frameBuffer = (char *) malloc(xres * yres * BPP); + server->alwaysShared = (1 == 1); + server->port = port; + server->ptrAddEvent = hook_mouseaction; + server->newClientHook = hook_newclient; + + if (password != NULL) { + char **passwds = malloc(sizeof(char **) * 2); + passwds[0] = password; + passwds[1] = 0; + server->authPasswdData = (void *) passwds; + server->passwordCheck = rfbCheckPasswordByList; + } + if (javaClassFiles != NULL) { + server->httpDir = javaClassFiles; + server->httpEnableProxyConnect = TRUE; + server->httpPort = httpPort; + } + /* Initialize the server */ + rfbInitServer(server); + + /* set width/height */ + DROWS = yres; + DCOLS = xres; + + /* set timestamp */ + gettimeofday(&startDriver, NULL); + + return 0; +} + +/****************************************/ +/*** widget callbacks ***/ +/****************************************/ + + +/* using drv_generic_text_draw(W) */ +/* using drv_generic_text_icon_draw(W) */ +/* using drv_generic_text_bar_draw(W) */ +/* using drv_generic_gpio_draw(W) */ + + +/****************************************/ +/*** exported functions ***/ +/****************************************/ + + +/* list models */ +int drv_vnc_list(void) +{ + printf("vnc server"); + return 0; +} + + +/* initialize driver & display */ +int drv_vnc_init(const char *section, const int quiet) +{ + int ret; + + /* real worker functions */ + drv_generic_graphic_real_blit = drv_vnc_blit; + drv_generic_keypad_real_press = drv_vnc_keypad; + + /* start display */ + if ((ret = drv_vnc_start(section)) != 0) + return ret; + + /* initialize generic graphic driver */ + if ((ret = drv_generic_graphic_init(section, Name)) != 0) + return ret; + + /* initialize generic key pad driver */ + if ((ret = drv_generic_keypad_init(section, Name)) != 0) + return ret; + + if (!quiet) { + char buffer[40]; + qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); + if (drv_generic_graphic_greet(buffer, NULL)) { + sleep(3); + drv_generic_graphic_clear(); + } + } + + return 0; +} + + +/* close driver & display */ +int drv_vnc_quit(const int quiet) +{ + info("%s: shutting down.", Name); + + /* clear display */ + drv_generic_graphic_clear(); + + /* say goodbye... */ + if (!quiet) { + drv_generic_graphic_greet("goodbye!", NULL); + } + + drv_generic_graphic_quit(); + drv_generic_keypad_quit(); + if (password != NULL) { + free(password); + } + if (javaClassFiles != NULL) { + free(javaClassFiles); + } + + debug("closing connection"); + drv_vnc_close(); + + return (0); +} + + +DRIVER drv_vnc = { + .name = Name, + .list = drv_vnc_list, + .init = drv_vnc_init, + .quit = drv_vnc_quit, +}; -- cgit v1.2.3