blob: efc46c13fb509096b50100ad379331fb95fed6bc [file] [log] [blame]
adamdunkels2d015312003-07-02 21:34:00 +00001/*
2 * Copyright (c) 2001, Adam Dunkels
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
adamdunkels1d2858f2004-06-06 05:54:13 +000013 * 3. The name of the author may not be used to endorse or promote
adamdunkels2d015312003-07-02 21:34:00 +000014 * products derived from this software without specific prior
15 * written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * This file is part of the uIP TCP/IP stack.
30 *
adamdunkels7790abe2004-09-01 18:18:39 +000031 * $Id: vnc-out.c,v 1.7 2004/09/01 18:18:39 adamdunkels Exp $
adamdunkels2d015312003-07-02 21:34:00 +000032 *
33 */
34
35#include "uip.h"
36#include "vnc-server.h"
37#include "vnc-out.h"
38
39#include "libconio.h"
40
adamdunkels033f0842003-09-04 19:37:13 +000041#include "ctk-vncserver-conf.h"
42
adamdunkels2d015312003-07-02 21:34:00 +000043#include "ctk-vncfont.h"
44
45#include "ctk-arch.h"
46
47#include "ctk-mouse.h"
48
adamdunkels91acf262003-08-12 21:11:09 +000049#ifdef WITH_AVR
adamdunkels2d015312003-07-02 21:34:00 +000050#include <avr/pgmspace.h>
51#else
52#define memcpy_P memcpy
adamdunkels91acf262003-08-12 21:11:09 +000053#endif /* WITH_AVR */
adamdunkels2d015312003-07-02 21:34:00 +000054
55#define CHARS_WIDTH LIBCONIO_CONF_SCREEN_WIDTH
56#define CHARS_HEIGHT LIBCONIO_CONF_SCREEN_HEIGHT
57
58#define SCREEN_X 10
59#define SCREEN_Y 8
60
adamdunkels78366292004-08-09 20:31:37 +000061#define SCREEN_WIDTH (CHARS_WIDTH * CTK_VNCFONT_WIDTH + 2 * SCREEN_X) /*420*/
62#define SCREEN_HEIGHT (CHARS_HEIGHT * CTK_VNCFONT_HEIGHT + 2 * SCREEN_Y) /*300*/
adamdunkels2d015312003-07-02 21:34:00 +000063#define BORDER_COLOR 0x00
adamdunkels2d015312003-07-02 21:34:00 +000064#define SCREEN_COLOR 0x00 /*0xc0*/
65
adamdunkels78366292004-08-09 20:31:37 +000066#ifndef CH_HOME
67#define CH_HOME 0x50
68#endif
69
70#ifndef CH_TAB
71#define CH_TAB 0x09
72#endif
73
74
adamdunkels2d015312003-07-02 21:34:00 +000075#define BGR(b,g,r) (((b) << 6) | (g) << 3 | (r))
76
adamdunkels2d015312003-07-02 21:34:00 +000077
adamdunkelsb81e5602003-09-02 21:46:41 +000078static const u8_t menucolor[] = {
adamdunkels1d2858f2004-06-06 05:54:13 +000079 BGR(3,7,7), /* Background. */
adamdunkels78366292004-08-09 20:31:37 +000080 BGR(2,6,6), /* Anti-alias font color. */
adamdunkels2d015312003-07-02 21:34:00 +000081 BGR(0,0,0), /* Font color. */
82};
83
84
adamdunkelsb81e5602003-09-02 21:46:41 +000085static const u8_t activemenucolor[] = {
adamdunkels1d2858f2004-06-06 05:54:13 +000086 BGR(0,0,0), /* Background. */
87 BGR(2,5,5), /* Anti-alias font color. */
88 BGR(3,7,7), /* Font color. */
adamdunkels2d015312003-07-02 21:34:00 +000089};
90
adamdunkels1d2858f2004-06-06 05:54:13 +000091#define W BGR(3,7,7)
92#define B BGR(0,0,0)
93#define G0 BGR(0,2,2)
94#define G1 BGR(1,2,2)
95#define G2 BGR(1,3,3)
96#define G3 BGR(2,4,4)
97#define G4 BGR(2,5,5)
98#define G5 BGR(2,6,6)
adamdunkels2d015312003-07-02 21:34:00 +000099
adamdunkels78366292004-08-09 20:31:37 +0000100#define BG BGR(3,4,4)
adamdunkels1d2858f2004-06-06 05:54:13 +0000101
102static const unsigned char backgroundcolor[] = {BG};
adamdunkels2d015312003-07-02 21:34:00 +0000103
adamdunkelsb81e5602003-09-02 21:46:41 +0000104static const unsigned char wincol[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000105 {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),G2,G3,G4};
106 /* {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),BGR(1,0,0),BGR(2,0,0),BGR(2,1,1)}; */
adamdunkelsb81e5602003-09-02 21:46:41 +0000107static const unsigned char wincol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000108 {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),G4,G5,W};
109 /* {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)}; */
adamdunkelsb81e5602003-09-02 21:46:41 +0000110static const unsigned char wincol_d[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000111 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)};
adamdunkels2d015312003-07-02 21:34:00 +0000112
adamdunkelsb81e5602003-09-02 21:46:41 +0000113static const unsigned char sepcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000114 {BGR(2,5,5),BGR(2,6,6),BGR(3,6,6)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000115static const unsigned char sepcol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000116 {BGR(3,7,7),BGR(3,5,5),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000117static const unsigned char sepcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000118 {BGR(3,7,7),BGR(1,5,7),BGR(0,0,0)};
119
adamdunkelsb81e5602003-09-02 21:46:41 +0000120static const unsigned char labcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000121 {BGR(2,5,5),BGR(1,3,3),BGR(0,1,1)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000122static const unsigned char labcol_f[] =
adamdunkels78366292004-08-09 20:31:37 +0000123 {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000124static const unsigned char labcol_d[] =
adamdunkels78366292004-08-09 20:31:37 +0000125 {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0)};
adamdunkels2d015312003-07-02 21:34:00 +0000126
127
adamdunkelsb81e5602003-09-02 21:46:41 +0000128static const unsigned char butcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000129 {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
130 BGR(2,5,5),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000131static const unsigned char butcol_w[] =
adamdunkels2d015312003-07-02 21:34:00 +0000132 {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
133 BGR(2,5,5),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000134static const unsigned char butcol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000135 {G5,G4,B,BGR(3,5,5),BGR(3,6,6),BGR(3,7,7),
adamdunkels2d015312003-07-02 21:34:00 +0000136 BGR(3,6,6),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000137static const unsigned char butcol_fw[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000138 {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0),BGR(1,3,3),BGR(2,7,7),BGR(3,7,7),
139 BGR(3,6,6),BGR(3,7,7)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000140static const unsigned char butcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000141 {BGR(2,3,3),BGR(2,5,5),BGR(3,6,6),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
142 BGR(3,7,7),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000143static const unsigned char butcol_dw[] =
adamdunkels2d015312003-07-02 21:34:00 +0000144 {BGR(0,0,0),BGR(2,5,5),BGR(3,7,7),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
145 BGR(3,7,7),BGR(2,5,5)};
146
147
adamdunkelsb81e5602003-09-02 21:46:41 +0000148static const unsigned char hlcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000149 {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000150static const unsigned char hlcol_w[] =
adamdunkels2d015312003-07-02 21:34:00 +0000151 {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000152static const unsigned char hlcol_f[] =
adamdunkels78366292004-08-09 20:31:37 +0000153 {BGR(3,7,7),BGR(3,5,5),BGR(3,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000154static const unsigned char hlcol_fw[] =
adamdunkels78366292004-08-09 20:31:37 +0000155 {BGR(3,7,7),BGR(3,6,7),BGR(3,7,7)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000156static const unsigned char hlcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000157 {BGR(3,7,7),BGR(3,5,5),BGR(2,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000158static const unsigned char hlcol_dw[] =
adamdunkels2d015312003-07-02 21:34:00 +0000159 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
160
adamdunkelsb81e5602003-09-02 21:46:41 +0000161static const unsigned char iconcol[] =
adamdunkels78366292004-08-09 20:31:37 +0000162 {BG,G4,W,B,G1};
adamdunkelsb81e5602003-09-02 21:46:41 +0000163static const unsigned char iconcol_w[] =
adamdunkels78366292004-08-09 20:31:37 +0000164 {BGR(0,1,1),BGR(1,3,3),BGR(3,7,7), B,W};
adamdunkels2d015312003-07-02 21:34:00 +0000165
166
167
adamdunkels033f0842003-09-04 19:37:13 +0000168static const u8_t * const colortheme[] =
adamdunkels2d015312003-07-02 21:34:00 +0000169 {
170 backgroundcolor,
171
172 /* Window colors */
173 wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d,
174
175 /* Separator colors. */
176 sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d,
177
178 /* Label colors. */
179 labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d,
180
181 /* Button colors. */
182 butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
183
184 /* Hyperlink colors. */
185 hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw,
186
187 /* Textentry colors. */
188 butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
189
190 /* Icon colors */
191 iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w,
192
193 /* Menu colors. */
194 menucolor, activemenucolor, activemenucolor
195 };
196
197
198static int mouse_x, mouse_y, mouse_button;
199
adamdunkels78366292004-08-09 20:31:37 +0000200#ifdef CTK_VNCSERVER_CONF_SCREEN
201static u8_t *screen = CTK_VNCSERVER_CONF_SCREEN;
202#else
203static u8_t screen[CHARS_WIDTH * CHARS_HEIGHT];
204#endif
205
206#ifdef CTK_VNCSERVER_CONF_COLORSCREEN
207staitc u8_t *colorscreen = CTK_VNCSERVER_CONF_COLORSCREEN;
208#else
209static u8_t colorscreen[CHARS_WIDTH * CHARS_HEIGHT];
210#endif
adamdunkels2d015312003-07-02 21:34:00 +0000211
212
213#define PRINTF(x)
214
215/*-----------------------------------------------------------------------------------*/
adamdunkels033f0842003-09-04 19:37:13 +0000216#define MAX_ICONS CTK_VNCSERVER_CONF_MAX_ICONS
adamdunkels2d015312003-07-02 21:34:00 +0000217struct ctk_icon *icons[MAX_ICONS];
218
219unsigned char
220vnc_out_add_icon(struct ctk_icon *icon)
221{
222 u8_t i;
223 signed int empty;
224
225 empty = -1;
226 for(i = 0; i < MAX_ICONS; ++i) {
227 if(icon == icons[i]) {
228 return i;
229 }
230 if(icons[i] == NULL && empty < 0){
231 empty = i;
232 }
233 }
234
235 if(empty == -1) {
236 empty = 0;
237 }
238 icons[empty] = icon;
239 return empty;
240}
241
242/*-----------------------------------------------------------------------------------*/
243void
244vnc_out_init(void)
245{
246 u16_t i;
247 for(i = 0; i < CHARS_WIDTH * CHARS_HEIGHT; ++i) {
248 screen[i] = 0x20;
249 }
250}
251
252void
253vnc_out_update_screen(u8_t xpos, u8_t ypos, u8_t c, u8_t color)
254{
255 screen[xpos + ypos * CHARS_WIDTH] = c;
256 colorscreen[xpos + ypos * CHARS_WIDTH] = color;
257}
258/*-----------------------------------------------------------------------------------*/
259void
260vnc_out_update_area(struct vnc_server_state *vs,
261 u8_t x, u8_t y, u8_t w, u8_t h)
262{
263 u8_t x2, y2, ax2, ay2;
adamdunkels78366292004-08-09 20:31:37 +0000264 register struct vnc_server_update *a, *b;
adamdunkels2d015312003-07-02 21:34:00 +0000265
266 PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
267 x, y, w, h));
268
269 /* First check if we already have a full update queued. If so, there
270 is no need to put this update on the list. If there is a full
271 update, it is always the first one on the list, so there is no
272 need to go step the list in search for it. */
273
274 if(vs->updates_pending != NULL &&
275 vs->updates_pending->type == VNC_SERVER_UPDATE_FULL) {
276 PRINTF(("Update_area_connecion: full update already queued...\n"));
277 return;
278 }
279
280 again:
281
282 /* Check that we don't update the same area twice by going through
283 the list and search for an update with the same coordinates. */
284 for(a = vs->updates_pending; a != NULL; a = a->next) {
285 if(a->x == x && a->y == y &&
286 a->w == w && a->h == h) {
287 PRINTF(("Update_area_connecion: found equal area\n"));
288 return;
289 }
290 }
291
292 /* Next we check if this update covers an existing update. If so, we
293 remove the old update, expand this update so that it covers both
294 areas to be updated and run through the process again. */
295 b = NULL;
296 for(a = vs->updates_pending; a != NULL; a = a->next) {
297 x2 = x + w;
298 y2 = y + h;
299
300 ax2 = a->x + a->w;
301 ay2 = a->y + a->h;
302
303 /* Test the corners of both updates to see if they are inside the
304 other area. */
305#define INSIDE(x,y,x1,y1,x2,y2) ((x1) <= (x) && \
306 (x2) >= (x) && \
307 (y1) <= (y) && \
308 (y2) >= (y))
309 if(INSIDE(x, y, a->x, a->y, ax2, ay2) ||
310 INSIDE(x, y2, a->x, a->y, ax2, ay2) ||
311 INSIDE(x2, y2, a->x, a->y, ax2, ay2) ||
312 INSIDE(x2, y, a->x, a->y, ax2, ay2) ||
313 INSIDE(a->x, a->y, x, y, x2, y2) ||
314 INSIDE(a->x, ay2, x, y, x2, y2) ||
315 INSIDE(ax2, ay2, x, y, x2, y2) ||
316 INSIDE(ax2, a->y, x, y, x2, y2)) {
317
318 /* Remove the old update from the list. */
319 vnc_server_update_remove(vs, a);
320
321 /* Put it on the free list. */
322 vnc_server_update_free(vs, a);
323
324 PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
325 a->x, a->y, ax2, ay2));
326
327 /* Find the area that covers both updates. */
328#define MIN(a,b) ((a) < (b)? (a): (b))
329#define MAX(a,b) ((a) > (b)? (a): (b))
330 x = MIN(a->x, x);
331 y = MIN(a->y, y);
332 ax2 = MAX(ax2, x2);
333 ay2 = MAX(ay2, y2);
334 w = ax2 - x;
335 h = ay2 - y;
336
337 /* This should really be done by a recursive call to this
338 function: update_area_connection(vs, x, y, w, h); but because
339 some compilers might not be able to optimize away the
340 recursive call, we do it using a goto instead. */
341 PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
342 goto again;
343 }
344 if(b != NULL) {
345 b = b->next;
346 }
347 }
348
349 /* Allocate an update object by pulling it off the free list. If
350 there are no free objects, we go for a full update instead. */
351
352 /* a = vs->updates_free;*/
353 a = vnc_server_update_alloc(vs);
354 if(a == NULL) {
355 PRINTF(("Update_area_connecion: no free updates, doing full\n"));
356 /* Put all pending updates, except for one, on the free list. Use
357 the remaining update as a full update. */
358 while(vs->updates_pending != NULL) {
359 a = vs->updates_pending;
360 vnc_server_update_remove(vs, a);
361 vnc_server_update_free(vs, a);
362 }
363
364 a = vnc_server_update_alloc(vs);
365 a->type = VNC_SERVER_UPDATE_FULL;
366 vnc_server_update_add(vs, a);
367
368
369 } else {
370
371 PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
372 /* Else, we put the update object at the end of the pending
373 list. */
374 a->type = VNC_SERVER_UPDATE_PARTS;
375 a->x = x;
376 a->y = y;
377 a->w = w;
378 a->h = h;
379 vnc_server_update_add(vs, a);
380 }
381}
382/*-----------------------------------------------------------------------------------*/
383static void
adamdunkels78366292004-08-09 20:31:37 +0000384init_send_screen(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000385{
386 vs->sendmsg = SEND_SCREEN;
387 vs->x = vs->y = 0;
388 vs->x1 = vs->y1 = 0;
389 vs->x2 = vs->y2 = 0;
390 vs->w = CHARS_WIDTH;
391 vs->h = CHARS_HEIGHT;
392}
393/*-----------------------------------------------------------------------------------*/
394static void
adamdunkels78366292004-08-09 20:31:37 +0000395check_updates(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000396{
397
398 if(vs->state == VNC_RUNNING &&
399 vs->sendmsg == SEND_NONE &&
400 vs->updates_current == NULL) {
401 if(vs->updates_pending != NULL &&
402 vs->update_requested != 0) {
403 vs->update_requested = 0;
404 /* vs->updates_current = vs->updates_pending;
405 vs->updates_pending = vs->updates_pending->next;
406 vs->updates_current->next = NULL;*/
407
408 vs->updates_current = vnc_server_update_dequeue(vs);
409
410 if(vs->updates_current->type == VNC_SERVER_UPDATE_PARTS) {
411 vs->x = vs->x1 = vs->x2 = vs->updates_current->x;
412 vs->y = vs->y1 = vs->y2 = vs->updates_current->y;
413 vs->w = vs->updates_current->w;
414 vs->h = vs->updates_current->h;
415 vs->sendmsg = SEND_UPDATE;
416
417 PRINTF(("New update from (%d:%d) (%d:%d) to (%d:%d)\n",
418 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
419 vs->y + vs->h));
420 } else if(vs->updates_current->type == VNC_SERVER_UPDATE_FULL) {
421 init_send_screen(vs);
422 PRINTF(("New full update\n"));
423 }
424 }
425 }
426}
427/*-----------------------------------------------------------------------------------*/
adamdunkels78366292004-08-09 20:31:37 +0000428static u8_t tmp[CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT];
adamdunkels2d015312003-07-02 21:34:00 +0000429static void
adamdunkels91acf262003-08-12 21:11:09 +0000430makechar(CC_REGISTER_ARG char *ptr, u8_t x, u8_t y)
adamdunkels2d015312003-07-02 21:34:00 +0000431{
432 u8_t i, *tmpptr;
adamdunkels91acf262003-08-12 21:11:09 +0000433 register u8_t *colorscheme;
adamdunkels2d015312003-07-02 21:34:00 +0000434 unsigned char *bitmap;
435 u8_t b, b2;
436 u8_t xmove, ymove;
437 unsigned char c, color;
438
439 color = colorscreen[x + y * CHARS_WIDTH];
440 c = screen[x + y * CHARS_WIDTH];
441
adamdunkels78366292004-08-09 20:31:37 +0000442 colorscheme = (u8_t *)colortheme[color];
adamdunkels2d015312003-07-02 21:34:00 +0000443
444 /* First check if the character is a special icon character. These
445 are to be interpreted in a special manner: the first character of
446 the icon (the top left corner) has the highest bit set, but not
adamdunkels78366292004-08-09 20:31:37 +0000447 bit 6. All other characters have bit 6 set, and also count the
adamdunkels2d015312003-07-02 21:34:00 +0000448 number of positions away from the top left corner. Only the top
449 left corner contains enough information to identify the icon, all
450 other chars only contain the number of steps to reach the
451 identifying icon. */
452 if((c & 0x80) != 0) {
453 xmove = c & 0x0f;
454 ymove = (c & 0x30) >> 4;
455
456 c = colorscreen[x + y * CHARS_WIDTH];
adamdunkels78366292004-08-09 20:31:37 +0000457
adamdunkels91acf262003-08-12 21:11:09 +0000458 if(icons[c % MAX_ICONS] == NULL) {
459 c = 0;
460 }
adamdunkels7790abe2004-09-01 18:18:39 +0000461 bitmap = icons[c % MAX_ICONS]->bitmap;
462
463 if(bitmap != NULL) {
464 bitmap = bitmap + ymove * 8*3;
465 colorscheme = (u8_t *)colortheme[VNC_OUT_ICONCOLOR + (c >> 6)];
466 switch(xmove) {
467 case 0:
468 for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
469 b = bitmap[i];
470 *ptr++ = colorscheme[((b >> 7) & 0x01) << 2];
471 *ptr++ = colorscheme[((b >> 6) & 0x01) << 2];
472 *ptr++ = colorscheme[((b >> 5) & 0x01) << 2];
473 *ptr++ = colorscheme[((b >> 4) & 0x01) << 2];
474 *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
475 *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
476 }
477 break;
478 case 1:
479 for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
480 b = bitmap[i];
481 b2 = bitmap[i + 8];
482 *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
483 *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
484 *ptr++ = colorscheme[((b2 >> 7) & 0x01) << 2];
485 *ptr++ = colorscheme[((b2 >> 6) & 0x01) << 2];
486 *ptr++ = colorscheme[((b2 >> 5) & 0x01) << 2];
487 *ptr++ = colorscheme[((b2 >> 4) & 0x01) << 2];
488 }
489 break;
490 case 2:
491 for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
492 b = bitmap[i + 8];
493 b2 = bitmap[i + 16];
494 *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
495 *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
496 *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
497 *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
498 *ptr++ = colorscheme[((b2 >> 7) & 0x01) << 2];
499 *ptr++ = colorscheme[((b2 >> 6) & 0x01) << 2];
500 }
501 break;
502 case 3:
503 for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
504 b = bitmap[i + 16];
505 *ptr++ = colorscheme[((b >> 5) & 0x01) << 2];
506 *ptr++ = colorscheme[((b >> 4) & 0x01) << 2];
507 *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
508 *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
509 *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
510 *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
511 }
512 break;
adamdunkels2d015312003-07-02 21:34:00 +0000513 }
adamdunkels2d015312003-07-02 21:34:00 +0000514 }
515 } else {
adamdunkels78366292004-08-09 20:31:37 +0000516 memcpy_P(tmp, &ctk_vncfont[c * (CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT)],
517 CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT);
adamdunkels2d015312003-07-02 21:34:00 +0000518
519 tmpptr = tmp;
520
521
adamdunkels78366292004-08-09 20:31:37 +0000522 for(i = 0; i < CTK_VNCFONT_HEIGHT * CTK_VNCFONT_WIDTH; ++i) {
adamdunkels2d015312003-07-02 21:34:00 +0000523 *ptr++ = colorscheme[*tmpptr++];
524 }
525 }
526}
527/*-----------------------------------------------------------------------------------*/
528void
adamdunkels78366292004-08-09 20:31:37 +0000529vnc_out_new(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000530{
531 u8_t i;
532
533 vs->width = SCREEN_WIDTH;
534 vs->height = SCREEN_HEIGHT;
535 vs->x = vs->y = vs->x1 = vs->y1 = vs->x2 = vs->y2 = 0;
536 vs->w = CHARS_WIDTH;
537 vs->h = CHARS_HEIGHT;
538
539 /* Initialize the linked list of updates. */
540 for(i = 0; i < VNC_SERVER_MAX_UPDATES - 1; ++i) {
541 vs->updates_pool[i].next = &vs->updates_pool[i + 1];
542 }
543 vs->updates_pool[VNC_SERVER_MAX_UPDATES].next = NULL;
544
545 vs->updates_free = &vs->updates_pool[0];
546 vs->updates_pending = vs->updates_current = NULL;
547}
548/*-----------------------------------------------------------------------------------*/
549void
adamdunkels78366292004-08-09 20:31:37 +0000550vnc_out_send_blank(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000551{
adamdunkels78366292004-08-09 20:31:37 +0000552 register struct rfb_fb_update *umsg;
adamdunkels2d015312003-07-02 21:34:00 +0000553 u8_t *ptr;
554 u16_t len;
555 u8_t msglen;
556
557 vs->x = vs->y = 0;
558 vs->x2 = vs->y2 = 0;
559
560 umsg = (struct rfb_fb_update *)uip_appdata;
561
562 umsg->type = RFB_FB_UPDATE;
563 umsg->rects = HTONS(2);
564
565 ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
566 len = sizeof(struct rfb_fb_update);
567
568 msglen = vnc_server_draw_rect(ptr, 0, 0,
569 HTONS(SCREEN_WIDTH),
570 HTONS(SCREEN_HEIGHT),
571 BORDER_COLOR);
572
573
574 ptr += msglen;
575 len += msglen;
576
577 msglen = vnc_server_draw_rect(ptr,
578 HTONS(SCREEN_X), HTONS(SCREEN_Y),
579 HTONS(SCREEN_WIDTH - SCREEN_X * 2),
580 HTONS(SCREEN_HEIGHT - SCREEN_Y * 2),
581 SCREEN_COLOR);
582
583 uip_send(uip_appdata, len + msglen);
584
585 vs->sendmsg = SENT_BLANK;
586}
587/*-----------------------------------------------------------------------------------*/
588void
589vnc_out_send_screen(struct vnc_server_state *vs)
590{
591 vnc_out_send_update(vs);
592}
593/*-----------------------------------------------------------------------------------*/
adamdunkels033f0842003-09-04 19:37:13 +0000594static short tmpbuf[30];
adamdunkels2d015312003-07-02 21:34:00 +0000595void
adamdunkels78366292004-08-09 20:31:37 +0000596vnc_out_send_update(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000597{
598 u8_t x, y, x0;
599 u8_t msglen;
600 u16_t len, n;
601 u8_t *ptr;
602 struct rfb_fb_update *umsg;
adamdunkels78366292004-08-09 20:31:37 +0000603 register struct rfb_fb_update_rect_hdr *recthdr;
adamdunkels2d015312003-07-02 21:34:00 +0000604 struct rfb_rre_hdr *rrehdr;
605 u8_t c, color, lastcolor;
606 u8_t numblanks;
607
608 /* First, check if we need to feed the update function with a new
609 pending update. */
610 check_updates(vs);
611
612 /* PRINTF(("Sending Update from (%d:%d) (%d:%d) to (%d:%d)\n",
613 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
614 vs->y + vs->h));*/
615
616 umsg = (struct rfb_fb_update *)uip_appdata;
617
618 umsg->type = RFB_FB_UPDATE;
619
620 x0 = vs->x1;
621 n = 0;
622 msglen = 0;
623 ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
624 len = sizeof(struct rfb_fb_update);
625
626 /* Loop over all characters that are covered by this update. */
627 for(y = vs->y1; y < vs->y + vs->h; ++y) {
628 for(x = x0; x < vs->x + vs->w; ++x) {
629
630
631 /* First check if there are any blank space characters, and if
632 so, find out how many of them there are in a row. Instead of
633 sending the individual space characters as raw bitmaps, we
634 can send the entire string of blanks as a single color
635 rectangle instead. */
636
637 c = screen[x + y * CHARS_WIDTH];
638 numblanks = 0;
639 lastcolor = color = colorscreen[x + y * CHARS_WIDTH];
640
641 /* If the character is a blank, we continue reading characters
642 until we find one that has a different color, or one that is
643 not a blank. We must keep within the update rectangle, so we
644 make sure that the "x" variable does not increase beyond the
645 edge. The "numblanks" variable is used to keep track of how
646 many blank characters we have found. */
647 while(lastcolor == color &&
648 c == 0x20 &&
649 x < vs->x + vs->w) {
650 ++numblanks;
651
652
653 ++x;
654 lastcolor = color;
655 color = colorscreen[x + y * CHARS_WIDTH];
656 c = screen[x + y * CHARS_WIDTH];
657 }
658
659 if(numblanks > 0) {
660
661 /* PRINTF(("Found %d blanks (%d:%d -> %d:%d)\n",
662 numblanks, x - numblanks, y, x, y));*/
663
664 /* There were one or more blank characters, so we send out a
665 single color rectangle with the right width. But first we
666 make sure that there is enough space in the current TCP
667 segment to put the rectangle. If there isn't we have to
668 backtrack the "x" variable to where we found the first
669 blank character so that the next TCP segment will be able
670 to update this area instead. */
671
672 msglen = sizeof(struct rfb_fb_update_rect_hdr) +
adamdunkels033f0842003-09-04 19:37:13 +0000673 /*sizeof(struct rfb_rre_hdr)*/5;
adamdunkels2d015312003-07-02 21:34:00 +0000674
675 if(msglen >= uip_mss() - len) {
676 /* PRINTF(("Not enouch space for blanks (%d, left %d)\n",
677 msglen, uip_mss() - len));*/
678 /* There is not enough space in the segment, so we remember
679 where we were ... */
680 vs->x2 = x - numblanks;
681 vs->y2 = y;
682
683 /* ... and we break out of the loop. */
684 goto loopend;
685 }
686
687 /* We construct a rectangle with the right width and color. */
adamdunkels033f0842003-09-04 19:37:13 +0000688 /* recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
689 recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
690 rrehdr = (struct rfb_rre_hdr *)((char *)recthdr +
adamdunkels2d015312003-07-02 21:34:00 +0000691 sizeof(struct rfb_fb_update_rect_hdr));
692
693 /* PRINTF(("Blankign (%d:%d) to (%d:%d)\n",
adamdunkels78366292004-08-09 20:31:37 +0000694 (x - numblanks) * CTK_VNCFONT_WIDTH,
695 y * CTK_VNCFONT_HEIGHT,
696 CTK_VNCFONT_WIDTH * numblanks,
697 CTK_VNCFONT_HEIGHT));*/
adamdunkels2d015312003-07-02 21:34:00 +0000698 recthdr->rect.x = htons(SCREEN_X + (x - numblanks) *
adamdunkels78366292004-08-09 20:31:37 +0000699 CTK_VNCFONT_WIDTH);
700 recthdr->rect.y = htons(SCREEN_Y + y * CTK_VNCFONT_HEIGHT);
701 recthdr->rect.w = htons(CTK_VNCFONT_WIDTH * numblanks);
702 recthdr->rect.h = HTONS(CTK_VNCFONT_HEIGHT);
adamdunkels2d015312003-07-02 21:34:00 +0000703 recthdr->encoding[0] =
704 recthdr->encoding[1] =
705 recthdr->encoding[2] = 0;
706 recthdr->encoding[3] = RFB_ENC_RRE;
707
708 rrehdr->subrects[0] =
709 rrehdr->subrects[1] = 0;
710 rrehdr->bgpixel = colortheme[lastcolor][0];
711
712 --x;
713 } else {
714
715 /* So there were no blank characters. */
716
717 /* PRINTF(("An char at (%d:%d)\n", x, y));*/
718 /* First we must make sure that there is enough space in the
719 outgoing TCP segment. */
720
721 msglen = sizeof(struct rfb_fb_update_rect_hdr) +
adamdunkels78366292004-08-09 20:31:37 +0000722 CTK_VNCFONT_HEIGHT * CTK_VNCFONT_WIDTH;
adamdunkels2d015312003-07-02 21:34:00 +0000723 if(msglen >= uip_mss() - len) {
724 /* PRINTF(("Not enouch space for char (%d, left %d)\n",
725 msglen, uip_mss() - len));*/
726
727 /* There is not enough space in the segment, so we remember
728 where we were ... */
729 vs->x2 = x;
730 vs->y2 = y;
731
732 /* ... and we break out of the loop. */
733 goto loopend;
734 }
735
736 /* PRINTF(("ptr %p\n",ptr);*/
adamdunkels033f0842003-09-04 19:37:13 +0000737 /* recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
738 recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
adamdunkels2d015312003-07-02 21:34:00 +0000739
adamdunkels78366292004-08-09 20:31:37 +0000740 recthdr->rect.x = htons(SCREEN_X + x * CTK_VNCFONT_WIDTH);
741 recthdr->rect.y = htons(SCREEN_Y + y * CTK_VNCFONT_HEIGHT);
742 recthdr->rect.w = HTONS(CTK_VNCFONT_WIDTH);
743 recthdr->rect.h = HTONS(CTK_VNCFONT_HEIGHT);
adamdunkels2d015312003-07-02 21:34:00 +0000744 recthdr->encoding[0] =
745 recthdr->encoding[1] =
746 recthdr->encoding[2] = 0;
747 recthdr->encoding[3] = RFB_ENC_RAW;
adamdunkels91acf262003-08-12 21:11:09 +0000748
adamdunkels2d015312003-07-02 21:34:00 +0000749 makechar((u8_t *)recthdr +
750 sizeof(struct rfb_fb_update_rect_hdr),
751 x, y);
adamdunkels2d015312003-07-02 21:34:00 +0000752 }
adamdunkels033f0842003-09-04 19:37:13 +0000753 memcpy(ptr, tmpbuf, msglen);
754 PRINTF(("Msglen %d (%d:%d)\n", msglen, x, y));
adamdunkels2d015312003-07-02 21:34:00 +0000755 len += msglen;
756 ptr += msglen;
757 ++n;
758 }
759 x0 = vs->x;
760 }
761
762 loopend:
763
764 umsg->rects = htons(n);
765
766 if(y == vs->y + vs->h && x == vs->x + vs->w) {
767 vs->x2 = vs->y2 = 0;
768 }
769
770 if(n > 0) {
771 /* printf("Sending %d rects, %d bytes (%p, %p, %p)\n", n, len,
772 uip_appdata, umsg, ptr);*/
773 uip_send(uip_appdata, len);
774 }
775
776}
777/*-----------------------------------------------------------------------------------*/
adamdunkels033f0842003-09-04 19:37:13 +0000778#define NUMKEYS 20
adamdunkels2d015312003-07-02 21:34:00 +0000779static char keys[NUMKEYS];
780static int firstkey, lastkey;
781
782
783char
784vnc_out_keyavail(void)
785{
786 return firstkey != lastkey;
787}
788
789char
790vnc_out_getkey(void)
791{
792 char key;
793 key = keys[firstkey];
794
795 if(firstkey != lastkey) {
796 ++firstkey;
797 if(firstkey >= NUMKEYS) {
798 firstkey = 0;
799 }
800 }
801
802 return key;
803}
804
805void
806vnc_out_key_event(struct vnc_server_state *vs)
807{
adamdunkels78366292004-08-09 20:31:37 +0000808 register struct rfb_key_event *ev;
adamdunkels2d015312003-07-02 21:34:00 +0000809
810 ev = (struct rfb_key_event *)uip_appdata;
811
812 if(ev->down != 0) {
813 if(vs->sendmsg == SEND_NONE) {
814 vs->sendmsg = SEND_UPDATE;
815 }
816
817
818 if(ev->key[2] == 0 ||
819 (ev->key[2] == 0xff &&
820 (ev->key[3] == CH_HOME ||
821 ev->key[3] == CH_TAB ||
822 ev->key[3] == CH_ESC ||
823 ev->key[3] == CH_DEL ||
824 ev->key[3] == CH_ENTER ||
825 ev->key[3] == CH_CURS_LEFT ||
826 ev->key[3] == CH_CURS_UP ||
827 ev->key[3] == CH_CURS_RIGHT ||
828 ev->key[3] == CH_CURS_DOWN))) {
829
830 keys[lastkey] = ev->key[3];
831 ++lastkey;
832 if(lastkey >= NUMKEYS) {
833 lastkey = 0;
834 }
835 }
836 }
837
838 check_updates(vs);
839}
840/*-----------------------------------------------------------------------------------*/
841void
842vnc_out_pointer_event(struct vnc_server_state *vs)
843{
844 struct rfb_pointer_event *ev;
845 u16_t evx, evy;
846
847 ev = (struct rfb_pointer_event *)uip_appdata;
848
849 evx = htons(ev->x);
850 evy = htons(ev->y);
851
852 if(evx > SCREEN_X && evx < SCREEN_WIDTH - 2 * SCREEN_X &&
853 evy > SCREEN_Y && evy < SCREEN_HEIGHT - 2 * SCREEN_Y) {
854
855 mouse_button = ev->buttonmask & RFB_BUTTON_MASK1;
856
857 mouse_x = evx - SCREEN_X;
858 mouse_y = evy - SCREEN_Y;
859
860 check_updates(vs);
861 }
862}
863/*-----------------------------------------------------------------------------------*/
864void
adamdunkels78366292004-08-09 20:31:37 +0000865vnc_out_acked(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000866{
867 if(vs->state != VNC_RUNNING) {
868 return;
869 }
870 if(vs->sendmsg == SENT_BLANK) {
871 init_send_screen(vs);
872 } else if(vs->sendmsg == SEND_BLANK) {
873 /* Do nothing until sendmsg == SENT_BLANK. */
874 } else if(vs->sendmsg == SEND_SCREEN) {
875 /* When the screen has been fully drawn, ->x2 and ->y2 are both
876 set to 0 to indicate this.*/
877 if(vs->x2 == 0 && vs->y2 == 0) {
878 vs->sendmsg = SEND_NONE;
879
880 /* If there was an updaterequest for the entire screen, we can
881 clear that flag now. */
882 if(vs->updates_current != NULL) {
883 vnc_server_update_free(vs, vs->updates_current);
884 vs->updates_current = NULL;
885 }
886 check_updates(vs);
887 } else {
888 vs->x1 = vs->x2;
889 vs->y1 = vs->y2;
890 }
891
892 } else if(vs->sendmsg == SEND_UPDATE) {
893 if(vs->x2 == 0 && vs->y2 == 0) {
894 /* So, we have updated the area that we needed. We now check if
895 there have been any recent full screen update requests. If
896 so, we need to go to the SEND_SCREEN state. Else, we see if
897 there were more areas that needed to be updated and if so,
898 we'll continue with those. */
899
900 vs->sendmsg = SEND_NONE;
901
902 if(vs->updates_current != NULL) {
903 vnc_server_update_free(vs, vs->updates_current);
904 vs->updates_current = NULL;
905
906 }
907 check_updates(vs);
908#if 0
909 if(vs->updaterequest == VNC_SERVER_UPDATE_FULL) {
910 check_updates(vs);
911 } else {
912 vs->updatesptr2 = (vs->updatesptr2 + 1) %
913 VNC_SERVER_MAX_UPDATES;
914
915 /* If there are no more updates to do, we'll go back to the
916 SEND_NONE state. */
917 if(vs->updatesptr2 == vs->updatesptr) {
918 vs->updatetype = VNC_SERVER_UPDATE_NONE;
919 } else {
920 /* Otherwise, we continue to update the next area. */
921 vs->updaterequest = VNC_SERVER_UPDATE_PARTS;
922 check_updates(vs);
923 }
924 }
925#endif /* 0 */
926 } else {
927 vs->x1 = vs->x2;
928 vs->y1 = vs->y2;
929 }
930 } else {
931 vs->sendmsg = SEND_NONE;
932 }
933}
934/*-----------------------------------------------------------------------------------*/
935void
936vnc_out_poll(struct vnc_server_state *vs)
937{
938 /* PRINTF(("vs->state %d, sendmsg %d, updatetype %d, updatereq %d\n",
939 vs->state, vs->sendmsg, vs->updatetype, vs->updaterequest);*/
940
941 if(vs->state == VNC_RUNNING &&
942 vs->sendmsg == SEND_NONE) {
943 check_updates(vs);
944 vnc_server_send_data(vs);
945 }
946}
947/*-----------------------------------------------------------------------------------*/
adamdunkels78366292004-08-09 20:31:37 +0000948#if CTK_CONF_MOUSE_SUPPORT
adamdunkels2d015312003-07-02 21:34:00 +0000949void
950ctk_mouse_init(void)
951{
952
953}
954/*-----------------------------------------------------------------------------------*/
955unsigned short
956ctk_mouse_x(void)
957{
958 return mouse_x;
959}
960/*-----------------------------------------------------------------------------------*/
961unsigned short
962ctk_mouse_y(void)
963{
964 return mouse_y;
965}
966/*-----------------------------------------------------------------------------------*/
967unsigned char
adamdunkels2d015312003-07-02 21:34:00 +0000968ctk_mouse_button(void)
969{
970 return mouse_button;
971}
972/*-----------------------------------------------------------------------------------*/
973void
974ctk_mouse_hide(void)
975{
976}
977/*-----------------------------------------------------------------------------------*/
978void
979ctk_mouse_show(void)
980{
981}
982/*-----------------------------------------------------------------------------------*/
adamdunkels78366292004-08-09 20:31:37 +0000983#endif /* CTK_CONF_MOUSE_SUPPORT */