aboutsummaryrefslogtreecommitdiffstats
path: root/drv_vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drv_vnc.c')
-rw-r--r--drv_vnc.c547
1 files changed, 547 insertions, 0 deletions
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 <michu@neophob.com>
+ * Modified from sample code by:
+ * Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <rfb/rfb.h>
+
+/* struct timeval */
+#include <sys/time.h>
+
+#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,
+};