~siretart/lcd4linux/debian

0.1.1 by Reinhard Tartler
Import upstream version 0.11.0~svn1143
1
/* $Id: drv_vnc.c 1031 2009-04-15 21:34:51Z michux $
2
 * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_vnc.c $
3
 *
4
 * Libvncserver driver
5
 * 
6
 * Copyright (C) 2009 Michael Vogt <michu@neophob.com>
7
 * Modified from sample code by:
8
 * Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
9
 * Copyright (C) 2005, 2006, 2007, 2008, 2009 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
10
 *
11
 * This file is part of LCD4Linux.
12
 *
13
 * LCD4Linux is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2, or (at your option)
16
 * any later version.
17
 *
18
 * LCD4Linux is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
 *
27
 */
28
29
/* 
30
 *
31
 * exported fuctions:
32
 *
33
 * struct DRIVER drv_vnc
34
 *
35
 */
36
37
#include "config.h"
38
39
#include <stdlib.h>
40
#include <stdio.h>
41
#include <unistd.h>
42
#include <string.h>
43
#include <errno.h>
44
45
#include <rfb/rfb.h>
46
47
/* struct timeval */
48
#include <sys/time.h>
49
50
#include "debug.h"
51
#include "cfg.h"
52
#include "qprintf.h"
53
#include "udelay.h"
54
#include "plugin.h"
55
#include "widget.h"
56
#include "widget_text.h"
57
#include "widget_icon.h"
58
#include "widget_bar.h"
59
#include "widget_keypad.h"
60
#include "drv.h"
61
#include "drv_generic_graphic.h"
62
#include "drv_generic_keypad.h"
63
64
//todo:  key widget text
65
66
#define NO_MOUSE_BUTTON_PRESSED 0
67
#define LEFT_MOUSE_BUTTON_PRESSED 1
68
#define SLEEP_STEPS 1000
69
70
static char Name[] = "VNC";
71
72
static int xres = 320;		/* screen settings */
73
static int yres = 200;
74
static int BPP = 4;
75
static int max_clients = 2;	/* max connected clients */
76
static int osd_showtime = 2000;	/* time to display the osd in ms */
77
static int buttons = 2;		/* number of keypad buttons */
78
static int buttonsize = 50;	/* size of keypad buttons */
79
static int keypadxofs = 0;
80
static int keypadyofs = 0;
81
static int keypadgap = 0;
82
static int port = 5900;
83
static int httpPort = 5800;
84
static unsigned char framer = 0;
85
static unsigned char frameg = 0;
86
static unsigned char frameb = 0;
87
88
static rfbScreenInfoPtr server;	/* vnc device */
89
static struct timeval osd_timestamp;
90
static int show_keypad_osd = 0;	/* is the osd active? */
91
static int clientCount = 0;	/* currently connected clients */
92
static int mouse_x = 0;
93
static int mouse_y = 0;
94
static int mouse_stat_old = 0;
95
static int process_event = 0;
96
static long frames = 0;
97
static char *password;
98
static char *javaClassFiles;
99
static struct timeval startDriver;
100
static int maxfps = -1;
101
102
/* draws a simple rect, used to display keypad */
103
int draw_rect(int x, int y, int size, unsigned char col, char *buffer)
104
{
105
    int ofs, ofs2, i, ret;
106
    unsigned char colr, colg;
107
    colr = colg = col;
108
    ret = 0;
109
110
    /* check if mouse is in current rect */
111
    if (mouse_x > x && mouse_x < (x + size))
112
	if (mouse_y > y && mouse_y < (y + size)) {
113
	    colr = framer;
114
	    colg = frameg;
115
	    col = frameb;
116
	    ret = 1;
117
	}
118
119
    ofs2 = size * xres * BPP;
120
    for (i = x; i < x + size; i++) {
121
	ofs = (i + xres * y) * BPP;
122
	buffer[ofs + ofs2] = colr;
123
	buffer[ofs++] = colr;
124
	buffer[ofs + ofs2] = colg;
125
	buffer[ofs++] = colg;
126
	buffer[ofs + ofs2] = col;
127
	buffer[ofs++] = col;
128
    }
129
130
    ofs2 = size * BPP;
131
    for (i = y; i <= y + size; i++) {
132
	ofs = (i * xres + x) * BPP;
133
	buffer[ofs + ofs2] = colr;
134
	buffer[ofs++] = colr;
135
	buffer[ofs + ofs2] = colg;
136
	buffer[ofs++] = colg;
137
	buffer[ofs + ofs2] = col;
138
	buffer[ofs++] = col;
139
    }
140
    return ret;
141
}
142
143
void display_keypad()
144
{
145
    int i, rectx, recty;
146
    int active;
147
    for (i = 0; i < buttons; i++) {
148
	rectx = keypadxofs + (i * (buttonsize + keypadgap));
149
	recty = keypadyofs /*+ (i*(buttonsize+gap)) */ ;
150
	active = draw_rect(rectx, recty, buttonsize, 0, server->frameBuffer);
151
152
	/* if the lmb button is pressed and we didnt processed the event yet - do it now */
153
	if (active == 1 && process_event == 1) {
154
	    drv_generic_keypad_press(i + 1);
155
	    //debug("mouse in keypad nr %d", i);
156
	    process_event = 0;
157
	}
158
    }
159
}
160
161
/* called if a vnc client disconnects */
162
static void clientgone( __attribute__ ((unused)) rfbClientPtr cl)
163
{
164
    if (clientCount > 0)
165
	clientCount--;
166
    debug("%d clients connected", clientCount);
167
}
168
169
/* called if a vnc client connect */
170
static enum rfbNewClientAction hook_newclient(rfbClientPtr cl)
171
{
172
    if (clientCount < max_clients) {
173
	clientCount++;
174
	cl->clientGoneHook = clientgone;
175
	debug("%d clients connected", clientCount);
176
	return RFB_CLIENT_ACCEPT;
177
    } else {
178
	info("client refused due max. client connections (%d)", clientCount);
179
	return RFB_CLIENT_REFUSE;
180
    }
181
}
182
183
/* handle mouse action */
184
static void hook_mouseaction(int buttonMask, int x, int y, rfbClientPtr cl)
185
{
186
    if (x >= 0 && y >= 0 && x < xres && y < yres) {
187
	process_event = 0;
188
189
	/* process ONLY if mouse button is released. */
190
	if (buttonMask == NO_MOUSE_BUTTON_PRESSED && mouse_stat_old == LEFT_MOUSE_BUTTON_PRESSED) {
191
	    gettimeofday(&osd_timestamp, NULL);
192
	    process_event = 1;
193
	    mouse_x = x;
194
	    mouse_y = y;
195
	}
196
	//debug("btnMask: %d, old state: %d, processevent: %d", buttonMask, mouse_stat_old, process_event);
197
198
	/* show osd display if mouse is pressed */
199
	if (buttonMask == 1) {
200
	    gettimeofday(&osd_timestamp, NULL);
201
	    mouse_x = x;
202
	    mouse_y = y;
203
	    if (show_keypad_osd == 0) {
204
		/* no osd until yet, activate osd keypad ... */
205
		show_keypad_osd = 1;
206
	    }
207
	}
208
209
    }
210
211
    mouse_stat_old = buttonMask;
212
    rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
213
}
214
215
static int drv_vnc_keypad(const int num)
216
{
217
    int val = WIDGET_KEY_PRESSED;
218
219
    switch (num) {
220
    case 1:
221
	val += WIDGET_KEY_UP;
222
	break;
223
    case 2:
224
	val += WIDGET_KEY_DOWN;
225
	break;
226
    case 3:
227
	val += WIDGET_KEY_LEFT;
228
	break;
229
    case 4:
230
	val += WIDGET_KEY_RIGHT;
231
	break;
232
    case 5:
233
	val += WIDGET_KEY_CONFIRM;
234
	break;
235
    case 6:
236
	val += WIDGET_KEY_CANCEL;
237
	break;
238
    default:
239
	error("%s: unknown keypad value %d", Name, num);
240
    }
241
242
    return val;
243
}
244
245
/* init the driver, read config */
246
static int drv_vnc_open(const char *Section)
247
{
248
    int keypadcol;
249
    if (cfg_number(Section, "Xres", 320, 32, 2048, &xres) < 1) {
250
	info("[DRV_VNC] no '%s.Xres' entry from %s using default %d", Section, cfg_source(), xres);
251
    }
252
    if (cfg_number(Section, "Yres", 200, 32, 2048, &yres) < 1) {
253
	info("[DRV_VNC] no '%s.Yres' entry from %s using default %d", Section, cfg_source(), yres);
254
    }
255
    if (cfg_number(Section, "Bpp", 4, 1, 4, &BPP) < 1) {
256
	info("[DRV_VNC] no '%s.Bpp' entry from %s using default %d", Section, cfg_source(), BPP);
257
    }
258
    if (cfg_number(Section, "Maxclients", 2, 1, 64, &max_clients) < 1) {
259
	info("[DRV_VNC] no '%s.Maxclients' entry from %s using default %d", Section, cfg_source(), max_clients);
260
    }
261
    if (cfg_number(Section, "Osd_showtime", 2000, 500, 60000, &osd_showtime) < 1) {
262
	info("[DRV_VNC] no '%s.Osd_showtime' entry from %s using default %d", Section, cfg_source(), osd_showtime);
263
    }
264
    if (cfg_number(Section, "Buttons", 2, 0, 6, &buttons) < 1) {
265
	info("[DRV_VNC] no '%s.Buttons' entry from %s using default %d", Section, cfg_source(), buttons);
266
    }
267
    if (cfg_number(Section, "Buttonsize", 50, 8, 256, &buttonsize) < 1) {
268
	info("[DRV_VNC] no '%s.Buttonsize' entry from %s using default %d", Section, cfg_source(), buttonsize);
269
    }
270
    if (cfg_number(Section, "Keypadxofs", 0, 0, 4096, &keypadxofs) < 1) {
271
	info("[DRV_VNC] no '%s.Keypadxofs' entry from %s using default %d", Section, cfg_source(), keypadxofs);
272
    }
273
    if (cfg_number(Section, "Keypadyofs", 0, 0, 4096, &keypadyofs) < 1) {
274
	info("[DRV_VNC] no '%s.Keypadyofs' entry from %s using default %d", Section, cfg_source(), keypadyofs);
275
    }
276
    if (cfg_number(Section, "Keypadgap", 10, 0, 2048, &keypadgap) < 1) {
277
	info("[DRV_VNC] no '%s.Keypadgap' entry from %s using default %d", Section, cfg_source(), keypadgap);
278
    }
279
    if (cfg_number(Section, "Keypadcol", 255, 0, 0xffffff, &keypadcol) < 1) {
280
	info("[DRV_VNC] no '%s.Keypadcol' entry from %s using default red", Section, cfg_source());
281
	framer = 255;
282
    } else {
283
	framer = keypadcol & 0xff;
284
	frameg = (keypadcol & 0xff00) >> 8;
285
	frameb = (keypadcol & 0xff0000) >> 16;
286
    }
287
    if (cfg_number(Section, "Port", 5900, 1, 65535, &port) < 1) {
288
	info("[DRV_VNC] no '%s.Port' entry from %s using default %d", Section, cfg_source(), port);
289
    }
290
    if (cfg_number(Section, "HttpPort", 5800, 1, 65535, &httpPort) < 1) {
291
	info("[DRV_VNC] no '%s.HttpPort' entry from %s using default %d", Section, cfg_source(), httpPort);
292
    }
293
    if (cfg_number(Section, "Maxfps", -1, -1, 512, &maxfps) < 1) {
294
	info("[DRV_VNC] no '%s.Maxfps' entry from %s using default %d", Section, cfg_source(), maxfps);
295
    }
296
    password = cfg_get(Section, "Password", NULL);
297
    if (password != NULL) {
298
	info("[DRV_VNC] password enabled");
299
    }
300
    javaClassFiles = cfg_get(Section, "HttpDir", NULL);
301
    if (javaClassFiles != NULL) {
302
	info("[DRV_VNC] HTTP server enabled");
303
    }
304
    return 0;
305
}
306
307
/* shutdown driver, release allocated stuff */
308
static int drv_vnc_close(void)
309
{
310
    rfbShutdownServer(server, TRUE);
311
    free(server->frameBuffer);
312
    return 0;
313
}
314
315
316
/* actual blitting method */
317
static void drv_vnc_blit_it(const int row, const int col, const int height, const int width, unsigned char *buffer)
318
{
319
    static int sleep = 0;
320
    int r, c, ofs;
321
    RGBA p;
322
323
    for (r = row; r < row + height; r++) {
324
	for (c = col; c < col + width; c++) {
325
	    p = drv_generic_graphic_rgb(r, c);
326
	    ofs = (r * xres + c) * BPP;
327
	    buffer[ofs++] = p.R;
328
	    buffer[ofs++] = p.G;
329
	    buffer[ofs++] = p.B;
330
	    buffer[ofs] = 255;
331
	}
332
    }
333
334
    /* display osd keypad */
335
    if (show_keypad_osd == 1) {
336
	display_keypad();
337
338
	/* check if the osd should be disabled after the waittime */
339
	struct timeval now;
340
	gettimeofday(&now, NULL);
341
	int timedelta = (now.tv_sec - osd_timestamp.tv_sec) * 1000 + (now.tv_usec - osd_timestamp.tv_usec) / 1000;
342
343
	if (timedelta > osd_showtime) {
344
	    show_keypad_osd = 0;
345
	}
346
    }
347
    frames++;
348
    if ((frames % 10) == 0 && maxfps > 0) {
349
	struct timeval blittime;
350
	gettimeofday(&blittime, NULL);
351
	int time_since_start =
352
	    (blittime.tv_sec - startDriver.tv_sec) * 1000 + (blittime.tv_usec - startDriver.tv_usec) / 1000;
353
354
	/* if time changed since start of lcd4linux */
355
	if (time_since_start < 0) {
356
	    gettimeofday(&startDriver, NULL);
357
	    time_since_start =
358
		(blittime.tv_sec - startDriver.tv_sec) * 1000 + (blittime.tv_usec - startDriver.tv_usec) / 1000;
359
	    if (time_since_start == 0)
360
		time_since_start = 1;
361
	}
362
	//info("time :%d, frames: %d, sleep: %d", time_since_start, frames, sleep);
363
364
	int fps = (int) (1000 * frames / time_since_start);
365
366
	if (fps > maxfps) {
367
	    sleep += SLEEP_STEPS;
368
	}
369
370
	if (fps < maxfps && sleep >= SLEEP_STEPS) {
371
	    sleep -= SLEEP_STEPS;
372
	}
373
    }
374
    usleep(sleep);
375
376
}
377
378
379
static void drv_vnc_blit(const int row, const int col, const int height, const int width)
380
{
381
382
    if (rfbIsActive(server)) {
383
	drv_vnc_blit_it(row, col, height, width, (unsigned char *) server->frameBuffer);
384
385
	if (clientCount > 0) {
386
	    rfbMarkRectAsModified(server, 0, 0, xres, yres);
387
	}
388
	rfbProcessEvents(server, server->deferUpdateTime * 500);
389
    }
390
}
391
392
/* start graphic display */
393
static int drv_vnc_start(const char *section)
394
{
395
    char *s;
396
397
    s = cfg_get(section, "Font", "6x8");
398
    if (s == NULL || *s == '\0') {
399
	error("%s: no '%s.Font' entry from %s", Name, section, cfg_source());
400
	return -1;
401
    }
402
403
    XRES = -1;
404
    YRES = -1;
405
    if (sscanf(s, "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) {
406
	error("%s: bad Font '%s' from %s", Name, s, cfg_source());
407
	return -1;
408
    }
409
410
    /* Fixme: provider other fonts someday... */
411
    if (XRES != 6 && YRES != 8) {
412
	error("%s: bad Font '%s' from %s (only 6x8 at the moment)", Name, s, cfg_source());
413
	return -1;
414
    }
415
416
    /* open communication with the display */
417
    if (drv_vnc_open(section) < 0) {
418
	return -1;
419
    }
420
421
    /* you surely want to allocate a framebuffer or something... */
422
    server = rfbGetScreen(0, NULL, xres, yres, 8, 3, BPP);
423
    server->desktopName = "LCD4Linux VNC Driver";
424
    server->frameBuffer = (char *) malloc(xres * yres * BPP);
425
    server->alwaysShared = (1 == 1);
426
    server->port = port;
427
    server->ptrAddEvent = hook_mouseaction;
428
    server->newClientHook = hook_newclient;
429
430
    if (password != NULL) {
431
	char **passwds = malloc(sizeof(char **) * 2);
432
	passwds[0] = password;
433
	passwds[1] = 0;
434
	server->authPasswdData = (void *) passwds;
435
	server->passwordCheck = rfbCheckPasswordByList;
436
    }
437
    if (javaClassFiles != NULL) {
438
	server->httpDir = javaClassFiles;
439
	server->httpEnableProxyConnect = TRUE;
440
	server->httpPort = httpPort;
441
    }
442
    /* Initialize the server */
443
    rfbInitServer(server);
444
445
    /* set width/height */
446
    DROWS = yres;
447
    DCOLS = xres;
448
449
    /* set timestamp */
450
    gettimeofday(&startDriver, NULL);
451
452
    return 0;
453
}
454
455
/****************************************/
456
/***        widget callbacks          ***/
457
/****************************************/
458
459
460
/* using drv_generic_text_draw(W) */
461
/* using drv_generic_text_icon_draw(W) */
462
/* using drv_generic_text_bar_draw(W) */
463
/* using drv_generic_gpio_draw(W) */
464
465
466
/****************************************/
467
/***        exported functions        ***/
468
/****************************************/
469
470
471
/* list models */
472
int drv_vnc_list(void)
473
{
474
    printf("vnc server");
475
    return 0;
476
}
477
478
479
/* initialize driver & display */
480
int drv_vnc_init(const char *section, const int quiet)
481
{
482
    int ret;
483
484
    /* real worker functions */
485
    drv_generic_graphic_real_blit = drv_vnc_blit;
486
    drv_generic_keypad_real_press = drv_vnc_keypad;
487
488
    /* start display */
489
    if ((ret = drv_vnc_start(section)) != 0)
490
	return ret;
491
492
    /* initialize generic graphic driver */
493
    if ((ret = drv_generic_graphic_init(section, Name)) != 0)
494
	return ret;
495
496
    /* initialize generic key pad driver */
497
    if ((ret = drv_generic_keypad_init(section, Name)) != 0)
498
	return ret;
499
500
    if (!quiet) {
501
	char buffer[40];
502
	qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
503
	if (drv_generic_graphic_greet(buffer, NULL)) {
504
	    sleep(3);
505
	    drv_generic_graphic_clear();
506
	}
507
    }
508
509
    return 0;
510
}
511
512
513
/* close driver & display */
514
int drv_vnc_quit(const int quiet)
515
{
516
    info("%s: shutting down.", Name);
517
518
    /* clear display */
519
    drv_generic_graphic_clear();
520
521
    /* say goodbye... */
522
    if (!quiet) {
523
	drv_generic_graphic_greet("goodbye!", NULL);
524
    }
525
526
    drv_generic_graphic_quit();
527
    drv_generic_keypad_quit();
528
    if (password != NULL) {
529
	free(password);
530
    }
531
    if (javaClassFiles != NULL) {
532
	free(javaClassFiles);
533
    }
534
535
    debug("closing connection");
536
    drv_vnc_close();
537
538
    return (0);
539
}
540
541
542
DRIVER drv_vnc = {
543
    .name = Name,
544
    .list = drv_vnc_list,
545
    .init = drv_vnc_init,
546
    .quit = drv_vnc_quit,
547
};