blob: 24c4477079cda4de52c65d101bfc3f9a408017ef [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 *
adamdunkels1d2858f2004-06-06 05:54:13 +000031 * $Id: vnc-out.c,v 1.5 2004/06/06 05:54:13 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
61#define FONT_WIDTH 6
62#define FONT_HEIGHT 8
63
64#define SCREEN_WIDTH (CHARS_WIDTH * FONT_WIDTH + 2 * SCREEN_X) /*420*/
65#define SCREEN_HEIGHT (CHARS_HEIGHT * FONT_HEIGHT + 2 * SCREEN_Y) /*300*/
66#define BORDER_COLOR 0x00
adamdunkels2d015312003-07-02 21:34:00 +000067#define SCREEN_COLOR 0x00 /*0xc0*/
68
69#define BGR(b,g,r) (((b) << 6) | (g) << 3 | (r))
70
adamdunkels2d015312003-07-02 21:34:00 +000071
adamdunkelsb81e5602003-09-02 21:46:41 +000072static const u8_t menucolor[] = {
adamdunkels1d2858f2004-06-06 05:54:13 +000073 BGR(3,7,7), /* Background. */
74 BGR(2,5,5), /* Anti-alias font color. */
adamdunkels2d015312003-07-02 21:34:00 +000075 BGR(0,0,0), /* Font color. */
76};
77
78
adamdunkelsb81e5602003-09-02 21:46:41 +000079static const u8_t activemenucolor[] = {
adamdunkels1d2858f2004-06-06 05:54:13 +000080 BGR(0,0,0), /* Background. */
81 BGR(2,5,5), /* Anti-alias font color. */
82 BGR(3,7,7), /* Font color. */
adamdunkels2d015312003-07-02 21:34:00 +000083};
84
adamdunkels1d2858f2004-06-06 05:54:13 +000085#define W BGR(3,7,7)
86#define B BGR(0,0,0)
87#define G0 BGR(0,2,2)
88#define G1 BGR(1,2,2)
89#define G2 BGR(1,3,3)
90#define G3 BGR(2,4,4)
91#define G4 BGR(2,5,5)
92#define G5 BGR(2,6,6)
adamdunkels2d015312003-07-02 21:34:00 +000093
adamdunkels1d2858f2004-06-06 05:54:13 +000094#define BG BGR(1,2,2)
95
96static const unsigned char backgroundcolor[] = {BG};
adamdunkels2d015312003-07-02 21:34:00 +000097
adamdunkelsb81e5602003-09-02 21:46:41 +000098static const unsigned char wincol[] =
adamdunkels1d2858f2004-06-06 05:54:13 +000099 {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),G2,G3,G4};
100 /* {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 +0000101static const unsigned char wincol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000102 {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),G4,G5,W};
103 /* {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 +0000104static const unsigned char wincol_d[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000105 {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 +0000106
adamdunkelsb81e5602003-09-02 21:46:41 +0000107static const unsigned char sepcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000108 {BGR(2,5,5),BGR(2,6,6),BGR(3,6,6)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000109static const unsigned char sepcol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000110 {BGR(3,7,7),BGR(3,5,5),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000111static const unsigned char sepcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000112 {BGR(3,7,7),BGR(1,5,7),BGR(0,0,0)};
113
adamdunkelsb81e5602003-09-02 21:46:41 +0000114static const unsigned char labcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000115 {BGR(2,5,5),BGR(1,3,3),BGR(0,1,1)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000116static const unsigned char labcol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000117 {BGR(3,7,7),BGR(3,5,5),BGR(0,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000118static const unsigned char labcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000119 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
120
121
adamdunkelsb81e5602003-09-02 21:46:41 +0000122static const unsigned char butcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000123 {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
124 BGR(2,5,5),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000125static const unsigned char butcol_w[] =
adamdunkels2d015312003-07-02 21:34:00 +0000126 {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
127 BGR(2,5,5),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000128static const unsigned char butcol_f[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000129 {G5,G4,B,BGR(3,5,5),BGR(3,6,6),BGR(3,7,7),
adamdunkels2d015312003-07-02 21:34:00 +0000130 BGR(3,6,6),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000131static const unsigned char butcol_fw[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000132 {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0),BGR(1,3,3),BGR(2,7,7),BGR(3,7,7),
133 BGR(3,6,6),BGR(3,7,7)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000134static const unsigned char butcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000135 {BGR(2,3,3),BGR(2,5,5),BGR(3,6,6),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
136 BGR(3,7,7),BGR(2,5,5)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000137static const unsigned char butcol_dw[] =
adamdunkels2d015312003-07-02 21:34:00 +0000138 {BGR(0,0,0),BGR(2,5,5),BGR(3,7,7),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
139 BGR(3,7,7),BGR(2,5,5)};
140
141
adamdunkelsb81e5602003-09-02 21:46:41 +0000142static const unsigned char hlcol[] =
adamdunkels2d015312003-07-02 21:34:00 +0000143 {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000144static const unsigned char hlcol_w[] =
adamdunkels2d015312003-07-02 21:34:00 +0000145 {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000146static const unsigned char hlcol_f[] =
adamdunkels2d015312003-07-02 21:34:00 +0000147 {BGR(3,6,6),BGR(3,5,5),BGR(3,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000148static const unsigned char hlcol_fw[] =
adamdunkels2d015312003-07-02 21:34:00 +0000149 {BGR(3,6,6),BGR(3,6,7),BGR(3,7,7)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000150static const unsigned char hlcol_d[] =
adamdunkels2d015312003-07-02 21:34:00 +0000151 {BGR(3,7,7),BGR(3,5,5),BGR(2,0,0)};
adamdunkelsb81e5602003-09-02 21:46:41 +0000152static const unsigned char hlcol_dw[] =
adamdunkels2d015312003-07-02 21:34:00 +0000153 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
154
adamdunkelsb81e5602003-09-02 21:46:41 +0000155static const unsigned char iconcol[] =
adamdunkels1d2858f2004-06-06 05:54:13 +0000156 {BG,G5,W};
adamdunkelsb81e5602003-09-02 21:46:41 +0000157static const unsigned char iconcol_w[] =
adamdunkels2d015312003-07-02 21:34:00 +0000158 {BGR(0,1,1),BGR(2,5,5),BGR(3,7,7)};
159
160
161
adamdunkels033f0842003-09-04 19:37:13 +0000162static const u8_t * const colortheme[] =
adamdunkels2d015312003-07-02 21:34:00 +0000163 {
164 backgroundcolor,
165
166 /* Window colors */
167 wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d,
168
169 /* Separator colors. */
170 sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d,
171
172 /* Label colors. */
173 labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d,
174
175 /* Button colors. */
176 butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
177
178 /* Hyperlink colors. */
179 hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw,
180
181 /* Textentry colors. */
182 butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
183
184 /* Icon colors */
185 iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w,
186
187 /* Menu colors. */
188 menucolor, activemenucolor, activemenucolor
189 };
190
191
192static int mouse_x, mouse_y, mouse_button;
193
194static u8_t screen[CHARS_WIDTH * CHARS_HEIGHT],
195 colorscreen[CHARS_WIDTH * CHARS_HEIGHT];
196
197
198#define PRINTF(x)
199
200/*-----------------------------------------------------------------------------------*/
adamdunkels033f0842003-09-04 19:37:13 +0000201#define MAX_ICONS CTK_VNCSERVER_CONF_MAX_ICONS
adamdunkels2d015312003-07-02 21:34:00 +0000202struct ctk_icon *icons[MAX_ICONS];
203
204unsigned char
205vnc_out_add_icon(struct ctk_icon *icon)
206{
207 u8_t i;
208 signed int empty;
209
210 empty = -1;
211 for(i = 0; i < MAX_ICONS; ++i) {
212 if(icon == icons[i]) {
213 return i;
214 }
215 if(icons[i] == NULL && empty < 0){
216 empty = i;
217 }
218 }
219
220 if(empty == -1) {
221 empty = 0;
222 }
223 icons[empty] = icon;
224 return empty;
225}
226
227/*-----------------------------------------------------------------------------------*/
228void
229vnc_out_init(void)
230{
231 u16_t i;
232 for(i = 0; i < CHARS_WIDTH * CHARS_HEIGHT; ++i) {
233 screen[i] = 0x20;
234 }
235}
236
237void
238vnc_out_update_screen(u8_t xpos, u8_t ypos, u8_t c, u8_t color)
239{
240 screen[xpos + ypos * CHARS_WIDTH] = c;
241 colorscreen[xpos + ypos * CHARS_WIDTH] = color;
242}
243/*-----------------------------------------------------------------------------------*/
244void
245vnc_out_update_area(struct vnc_server_state *vs,
246 u8_t x, u8_t y, u8_t w, u8_t h)
247{
248 u8_t x2, y2, ax2, ay2;
249 struct vnc_server_update *a, *b;
250
251 PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
252 x, y, w, h));
253
254 /* First check if we already have a full update queued. If so, there
255 is no need to put this update on the list. If there is a full
256 update, it is always the first one on the list, so there is no
257 need to go step the list in search for it. */
258
259 if(vs->updates_pending != NULL &&
260 vs->updates_pending->type == VNC_SERVER_UPDATE_FULL) {
261 PRINTF(("Update_area_connecion: full update already queued...\n"));
262 return;
263 }
264
265 again:
266
267 /* Check that we don't update the same area twice by going through
268 the list and search for an update with the same coordinates. */
269 for(a = vs->updates_pending; a != NULL; a = a->next) {
270 if(a->x == x && a->y == y &&
271 a->w == w && a->h == h) {
272 PRINTF(("Update_area_connecion: found equal area\n"));
273 return;
274 }
275 }
276
277 /* Next we check if this update covers an existing update. If so, we
278 remove the old update, expand this update so that it covers both
279 areas to be updated and run through the process again. */
280 b = NULL;
281 for(a = vs->updates_pending; a != NULL; a = a->next) {
282 x2 = x + w;
283 y2 = y + h;
284
285 ax2 = a->x + a->w;
286 ay2 = a->y + a->h;
287
288 /* Test the corners of both updates to see if they are inside the
289 other area. */
290#define INSIDE(x,y,x1,y1,x2,y2) ((x1) <= (x) && \
291 (x2) >= (x) && \
292 (y1) <= (y) && \
293 (y2) >= (y))
294 if(INSIDE(x, y, a->x, a->y, ax2, ay2) ||
295 INSIDE(x, y2, a->x, a->y, ax2, ay2) ||
296 INSIDE(x2, y2, a->x, a->y, ax2, ay2) ||
297 INSIDE(x2, y, a->x, a->y, ax2, ay2) ||
298 INSIDE(a->x, a->y, x, y, x2, y2) ||
299 INSIDE(a->x, ay2, x, y, x2, y2) ||
300 INSIDE(ax2, ay2, x, y, x2, y2) ||
301 INSIDE(ax2, a->y, x, y, x2, y2)) {
302
303 /* Remove the old update from the list. */
304 vnc_server_update_remove(vs, a);
305
306 /* Put it on the free list. */
307 vnc_server_update_free(vs, a);
308
309 PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
310 a->x, a->y, ax2, ay2));
311
312 /* Find the area that covers both updates. */
313#define MIN(a,b) ((a) < (b)? (a): (b))
314#define MAX(a,b) ((a) > (b)? (a): (b))
315 x = MIN(a->x, x);
316 y = MIN(a->y, y);
317 ax2 = MAX(ax2, x2);
318 ay2 = MAX(ay2, y2);
319 w = ax2 - x;
320 h = ay2 - y;
321
322 /* This should really be done by a recursive call to this
323 function: update_area_connection(vs, x, y, w, h); but because
324 some compilers might not be able to optimize away the
325 recursive call, we do it using a goto instead. */
326 PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
327 goto again;
328 }
329 if(b != NULL) {
330 b = b->next;
331 }
332 }
333
334 /* Allocate an update object by pulling it off the free list. If
335 there are no free objects, we go for a full update instead. */
336
337 /* a = vs->updates_free;*/
338 a = vnc_server_update_alloc(vs);
339 if(a == NULL) {
340 PRINTF(("Update_area_connecion: no free updates, doing full\n"));
341 /* Put all pending updates, except for one, on the free list. Use
342 the remaining update as a full update. */
343 while(vs->updates_pending != NULL) {
344 a = vs->updates_pending;
345 vnc_server_update_remove(vs, a);
346 vnc_server_update_free(vs, a);
347 }
348
349 a = vnc_server_update_alloc(vs);
350 a->type = VNC_SERVER_UPDATE_FULL;
351 vnc_server_update_add(vs, a);
352
353
354 } else {
355
356 PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
357 /* Else, we put the update object at the end of the pending
358 list. */
359 a->type = VNC_SERVER_UPDATE_PARTS;
360 a->x = x;
361 a->y = y;
362 a->w = w;
363 a->h = h;
364 vnc_server_update_add(vs, a);
365 }
366}
367/*-----------------------------------------------------------------------------------*/
368static void
369init_send_screen(struct vnc_server_state *vs)
370{
371 vs->sendmsg = SEND_SCREEN;
372 vs->x = vs->y = 0;
373 vs->x1 = vs->y1 = 0;
374 vs->x2 = vs->y2 = 0;
375 vs->w = CHARS_WIDTH;
376 vs->h = CHARS_HEIGHT;
377}
378/*-----------------------------------------------------------------------------------*/
379static void
380check_updates(struct vnc_server_state *vs)
381{
382
383 if(vs->state == VNC_RUNNING &&
384 vs->sendmsg == SEND_NONE &&
385 vs->updates_current == NULL) {
386 if(vs->updates_pending != NULL &&
387 vs->update_requested != 0) {
388 vs->update_requested = 0;
389 /* vs->updates_current = vs->updates_pending;
390 vs->updates_pending = vs->updates_pending->next;
391 vs->updates_current->next = NULL;*/
392
393 vs->updates_current = vnc_server_update_dequeue(vs);
394
395 if(vs->updates_current->type == VNC_SERVER_UPDATE_PARTS) {
396 vs->x = vs->x1 = vs->x2 = vs->updates_current->x;
397 vs->y = vs->y1 = vs->y2 = vs->updates_current->y;
398 vs->w = vs->updates_current->w;
399 vs->h = vs->updates_current->h;
400 vs->sendmsg = SEND_UPDATE;
401
402 PRINTF(("New update from (%d:%d) (%d:%d) to (%d:%d)\n",
403 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
404 vs->y + vs->h));
405 } else if(vs->updates_current->type == VNC_SERVER_UPDATE_FULL) {
406 init_send_screen(vs);
407 PRINTF(("New full update\n"));
408 }
409 }
410 }
411}
412/*-----------------------------------------------------------------------------------*/
413static u8_t tmp[FONT_WIDTH * FONT_HEIGHT];
414static void
adamdunkels91acf262003-08-12 21:11:09 +0000415makechar(CC_REGISTER_ARG char *ptr, u8_t x, u8_t y)
adamdunkels2d015312003-07-02 21:34:00 +0000416{
417 u8_t i, *tmpptr;
adamdunkels91acf262003-08-12 21:11:09 +0000418 register u8_t *colorscheme;
adamdunkels2d015312003-07-02 21:34:00 +0000419 unsigned char *bitmap;
420 u8_t b, b2;
421 u8_t xmove, ymove;
422 unsigned char c, color;
423
424 color = colorscreen[x + y * CHARS_WIDTH];
425 c = screen[x + y * CHARS_WIDTH];
426
427 colorscheme = colortheme[color];
428
429 /* First check if the character is a special icon character. These
430 are to be interpreted in a special manner: the first character of
431 the icon (the top left corner) has the highest bit set, but not
432 but 6. All other characters have bit 6 set, and also count the
433 number of positions away from the top left corner. Only the top
434 left corner contains enough information to identify the icon, all
435 other chars only contain the number of steps to reach the
436 identifying icon. */
437 if((c & 0x80) != 0) {
438 xmove = c & 0x0f;
439 ymove = (c & 0x30) >> 4;
440
441 c = colorscreen[x + y * CHARS_WIDTH];
adamdunkels91acf262003-08-12 21:11:09 +0000442 if(icons[c % MAX_ICONS] == NULL) {
443 c = 0;
444 }
445 bitmap = icons[c % MAX_ICONS]->bitmap + ymove * 8*3;
446
adamdunkels2d015312003-07-02 21:34:00 +0000447 colorscheme = colortheme[VNC_OUT_ICONCOLOR + (c >> 6)];
448 switch(xmove) {
449 case 0:
450 for(i = 0; i < FONT_HEIGHT; ++i) {
451 b = bitmap[i];
452 *ptr++ = colorscheme[(b >> 7) & 0x01];
453 *ptr++ = colorscheme[(b >> 6) & 0x01];
454 *ptr++ = colorscheme[(b >> 5) & 0x01];
455 *ptr++ = colorscheme[(b >> 4) & 0x01];
456 *ptr++ = colorscheme[(b >> 3) & 0x01];
457 *ptr++ = colorscheme[(b >> 2) & 0x01];
458 }
459 break;
460 case 1:
461 for(i = 0; i < FONT_HEIGHT; ++i) {
462 b = bitmap[i];
463 b2 = bitmap[i + 8];
464 *ptr++ = colorscheme[(b >> 1) & 0x01];
465 *ptr++ = colorscheme[(b >> 0) & 0x01];
466 *ptr++ = colorscheme[(b2 >> 7) & 0x01];
467 *ptr++ = colorscheme[(b2 >> 6) & 0x01];
468 *ptr++ = colorscheme[(b2 >> 5) & 0x01];
469 *ptr++ = colorscheme[(b2 >> 4) & 0x01];
470 }
471 break;
472 case 2:
473 for(i = 0; i < FONT_HEIGHT; ++i) {
474 b = bitmap[i+8];
475 b2 = bitmap[i+16];
476 *ptr++ = colorscheme[(b >> 3) & 0x01];
477 *ptr++ = colorscheme[(b >> 2) & 0x01];
478 *ptr++ = colorscheme[(b >> 1) & 0x01];
479 *ptr++ = colorscheme[(b >> 0) & 0x01];
480 *ptr++ = colorscheme[(b2 >> 7) & 0x01];
481 *ptr++ = colorscheme[(b2 >> 6) & 0x01];
482 }
483 break;
484 case 3:
485 for(i = 0; i < FONT_HEIGHT; ++i) {
486 b = bitmap[i+16];
487 *ptr++ = colorscheme[(b >> 5) & 0x01];
488 *ptr++ = colorscheme[(b >> 4) & 0x01];
489 *ptr++ = colorscheme[(b >> 3) & 0x01];
490 *ptr++ = colorscheme[(b >> 2) & 0x01];
491 *ptr++ = colorscheme[(b >> 1) & 0x01];
492 *ptr++ = colorscheme[(b >> 0) & 0x01];
493 }
494 break;
495 }
496 } else {
497 memcpy_P(tmp, &ctk_vncfont[c * (FONT_WIDTH * FONT_HEIGHT)],
498 FONT_WIDTH * FONT_HEIGHT);
499
500 tmpptr = tmp;
501
502
503 for(i = 0; i < FONT_HEIGHT * FONT_WIDTH; ++i) {
504 *ptr++ = colorscheme[*tmpptr++];
505 }
506 }
507}
508/*-----------------------------------------------------------------------------------*/
509void
510vnc_out_new(struct vnc_server_state *vs)
511{
512 u8_t i;
513
514 vs->width = SCREEN_WIDTH;
515 vs->height = SCREEN_HEIGHT;
516 vs->x = vs->y = vs->x1 = vs->y1 = vs->x2 = vs->y2 = 0;
517 vs->w = CHARS_WIDTH;
518 vs->h = CHARS_HEIGHT;
519
520 /* Initialize the linked list of updates. */
521 for(i = 0; i < VNC_SERVER_MAX_UPDATES - 1; ++i) {
522 vs->updates_pool[i].next = &vs->updates_pool[i + 1];
523 }
524 vs->updates_pool[VNC_SERVER_MAX_UPDATES].next = NULL;
525
526 vs->updates_free = &vs->updates_pool[0];
527 vs->updates_pending = vs->updates_current = NULL;
528}
529/*-----------------------------------------------------------------------------------*/
530void
531vnc_out_send_blank(struct vnc_server_state *vs)
532{
533 struct rfb_fb_update *umsg;
534 u8_t *ptr;
535 u16_t len;
536 u8_t msglen;
537
538 vs->x = vs->y = 0;
539 vs->x2 = vs->y2 = 0;
540
541 umsg = (struct rfb_fb_update *)uip_appdata;
542
543 umsg->type = RFB_FB_UPDATE;
544 umsg->rects = HTONS(2);
545
546 ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
547 len = sizeof(struct rfb_fb_update);
548
549 msglen = vnc_server_draw_rect(ptr, 0, 0,
550 HTONS(SCREEN_WIDTH),
551 HTONS(SCREEN_HEIGHT),
552 BORDER_COLOR);
553
554
555 ptr += msglen;
556 len += msglen;
557
558 msglen = vnc_server_draw_rect(ptr,
559 HTONS(SCREEN_X), HTONS(SCREEN_Y),
560 HTONS(SCREEN_WIDTH - SCREEN_X * 2),
561 HTONS(SCREEN_HEIGHT - SCREEN_Y * 2),
562 SCREEN_COLOR);
563
564 uip_send(uip_appdata, len + msglen);
565
566 vs->sendmsg = SENT_BLANK;
567}
568/*-----------------------------------------------------------------------------------*/
569void
570vnc_out_send_screen(struct vnc_server_state *vs)
571{
572 vnc_out_send_update(vs);
573}
574/*-----------------------------------------------------------------------------------*/
adamdunkels033f0842003-09-04 19:37:13 +0000575static short tmpbuf[30];
adamdunkels2d015312003-07-02 21:34:00 +0000576void
577vnc_out_send_update(struct vnc_server_state *vs)
578{
579 u8_t x, y, x0;
580 u8_t msglen;
581 u16_t len, n;
582 u8_t *ptr;
583 struct rfb_fb_update *umsg;
584 struct rfb_fb_update_rect_hdr *recthdr;
585 struct rfb_rre_hdr *rrehdr;
586 u8_t c, color, lastcolor;
587 u8_t numblanks;
588
589 /* First, check if we need to feed the update function with a new
590 pending update. */
591 check_updates(vs);
592
593 /* PRINTF(("Sending Update from (%d:%d) (%d:%d) to (%d:%d)\n",
594 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
595 vs->y + vs->h));*/
596
597 umsg = (struct rfb_fb_update *)uip_appdata;
598
599 umsg->type = RFB_FB_UPDATE;
600
601 x0 = vs->x1;
602 n = 0;
603 msglen = 0;
604 ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
605 len = sizeof(struct rfb_fb_update);
606
607 /* Loop over all characters that are covered by this update. */
608 for(y = vs->y1; y < vs->y + vs->h; ++y) {
609 for(x = x0; x < vs->x + vs->w; ++x) {
610
611
612 /* First check if there are any blank space characters, and if
613 so, find out how many of them there are in a row. Instead of
614 sending the individual space characters as raw bitmaps, we
615 can send the entire string of blanks as a single color
616 rectangle instead. */
617
618 c = screen[x + y * CHARS_WIDTH];
619 numblanks = 0;
620 lastcolor = color = colorscreen[x + y * CHARS_WIDTH];
621
622 /* If the character is a blank, we continue reading characters
623 until we find one that has a different color, or one that is
624 not a blank. We must keep within the update rectangle, so we
625 make sure that the "x" variable does not increase beyond the
626 edge. The "numblanks" variable is used to keep track of how
627 many blank characters we have found. */
628 while(lastcolor == color &&
629 c == 0x20 &&
630 x < vs->x + vs->w) {
631 ++numblanks;
632
633
634 ++x;
635 lastcolor = color;
636 color = colorscreen[x + y * CHARS_WIDTH];
637 c = screen[x + y * CHARS_WIDTH];
638 }
639
640 if(numblanks > 0) {
641
642 /* PRINTF(("Found %d blanks (%d:%d -> %d:%d)\n",
643 numblanks, x - numblanks, y, x, y));*/
644
645 /* There were one or more blank characters, so we send out a
646 single color rectangle with the right width. But first we
647 make sure that there is enough space in the current TCP
648 segment to put the rectangle. If there isn't we have to
649 backtrack the "x" variable to where we found the first
650 blank character so that the next TCP segment will be able
651 to update this area instead. */
652
653 msglen = sizeof(struct rfb_fb_update_rect_hdr) +
adamdunkels033f0842003-09-04 19:37:13 +0000654 /*sizeof(struct rfb_rre_hdr)*/5;
adamdunkels2d015312003-07-02 21:34:00 +0000655
656 if(msglen >= uip_mss() - len) {
657 /* PRINTF(("Not enouch space for blanks (%d, left %d)\n",
658 msglen, uip_mss() - len));*/
659 /* There is not enough space in the segment, so we remember
660 where we were ... */
661 vs->x2 = x - numblanks;
662 vs->y2 = y;
663
664 /* ... and we break out of the loop. */
665 goto loopend;
666 }
667
668 /* We construct a rectangle with the right width and color. */
adamdunkels033f0842003-09-04 19:37:13 +0000669 /* recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
670 recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
671 rrehdr = (struct rfb_rre_hdr *)((char *)recthdr +
adamdunkels2d015312003-07-02 21:34:00 +0000672 sizeof(struct rfb_fb_update_rect_hdr));
673
674 /* PRINTF(("Blankign (%d:%d) to (%d:%d)\n",
675 (x - numblanks) * FONT_WIDTH,
676 y * FONT_HEIGHT,
677 FONT_WIDTH * numblanks,
678 FONT_HEIGHT));*/
679 recthdr->rect.x = htons(SCREEN_X + (x - numblanks) *
680 FONT_WIDTH);
681 recthdr->rect.y = htons(SCREEN_Y + y * FONT_HEIGHT);
682 recthdr->rect.w = htons(FONT_WIDTH * numblanks);
683 recthdr->rect.h = HTONS(FONT_HEIGHT);
684 recthdr->encoding[0] =
685 recthdr->encoding[1] =
686 recthdr->encoding[2] = 0;
687 recthdr->encoding[3] = RFB_ENC_RRE;
688
689 rrehdr->subrects[0] =
690 rrehdr->subrects[1] = 0;
691 rrehdr->bgpixel = colortheme[lastcolor][0];
692
693 --x;
694 } else {
695
696 /* So there were no blank characters. */
697
698 /* PRINTF(("An char at (%d:%d)\n", x, y));*/
699 /* First we must make sure that there is enough space in the
700 outgoing TCP segment. */
701
702 msglen = sizeof(struct rfb_fb_update_rect_hdr) +
703 FONT_HEIGHT * FONT_WIDTH;
704 if(msglen >= uip_mss() - len) {
705 /* PRINTF(("Not enouch space for char (%d, left %d)\n",
706 msglen, uip_mss() - len));*/
707
708 /* There is not enough space in the segment, so we remember
709 where we were ... */
710 vs->x2 = x;
711 vs->y2 = y;
712
713 /* ... and we break out of the loop. */
714 goto loopend;
715 }
716
717 /* PRINTF(("ptr %p\n",ptr);*/
adamdunkels033f0842003-09-04 19:37:13 +0000718 /* recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
719 recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
adamdunkels2d015312003-07-02 21:34:00 +0000720
721 recthdr->rect.x = htons(SCREEN_X + x * FONT_WIDTH);
722 recthdr->rect.y = htons(SCREEN_Y + y * FONT_HEIGHT);
723 recthdr->rect.w = HTONS(FONT_WIDTH);
724 recthdr->rect.h = HTONS(FONT_HEIGHT);
725 recthdr->encoding[0] =
726 recthdr->encoding[1] =
727 recthdr->encoding[2] = 0;
728 recthdr->encoding[3] = RFB_ENC_RAW;
adamdunkels91acf262003-08-12 21:11:09 +0000729
adamdunkels2d015312003-07-02 21:34:00 +0000730 makechar((u8_t *)recthdr +
731 sizeof(struct rfb_fb_update_rect_hdr),
732 x, y);
adamdunkels2d015312003-07-02 21:34:00 +0000733 }
adamdunkels033f0842003-09-04 19:37:13 +0000734 memcpy(ptr, tmpbuf, msglen);
735 PRINTF(("Msglen %d (%d:%d)\n", msglen, x, y));
adamdunkels2d015312003-07-02 21:34:00 +0000736 len += msglen;
737 ptr += msglen;
738 ++n;
739 }
740 x0 = vs->x;
741 }
742
743 loopend:
744
745 umsg->rects = htons(n);
746
747 if(y == vs->y + vs->h && x == vs->x + vs->w) {
748 vs->x2 = vs->y2 = 0;
749 }
750
751 if(n > 0) {
752 /* printf("Sending %d rects, %d bytes (%p, %p, %p)\n", n, len,
753 uip_appdata, umsg, ptr);*/
754 uip_send(uip_appdata, len);
755 }
756
757}
758/*-----------------------------------------------------------------------------------*/
adamdunkels033f0842003-09-04 19:37:13 +0000759#define NUMKEYS 20
adamdunkels2d015312003-07-02 21:34:00 +0000760static char keys[NUMKEYS];
761static int firstkey, lastkey;
762
763
764char
765vnc_out_keyavail(void)
766{
767 return firstkey != lastkey;
768}
769
770char
771vnc_out_getkey(void)
772{
773 char key;
774 key = keys[firstkey];
775
776 if(firstkey != lastkey) {
777 ++firstkey;
778 if(firstkey >= NUMKEYS) {
779 firstkey = 0;
780 }
781 }
782
783 return key;
784}
785
786void
787vnc_out_key_event(struct vnc_server_state *vs)
788{
789 struct rfb_key_event *ev;
790
791 ev = (struct rfb_key_event *)uip_appdata;
792
793 if(ev->down != 0) {
794 if(vs->sendmsg == SEND_NONE) {
795 vs->sendmsg = SEND_UPDATE;
796 }
797
798
799 if(ev->key[2] == 0 ||
800 (ev->key[2] == 0xff &&
801 (ev->key[3] == CH_HOME ||
802 ev->key[3] == CH_TAB ||
803 ev->key[3] == CH_ESC ||
804 ev->key[3] == CH_DEL ||
805 ev->key[3] == CH_ENTER ||
806 ev->key[3] == CH_CURS_LEFT ||
807 ev->key[3] == CH_CURS_UP ||
808 ev->key[3] == CH_CURS_RIGHT ||
809 ev->key[3] == CH_CURS_DOWN))) {
810
811 keys[lastkey] = ev->key[3];
812 ++lastkey;
813 if(lastkey >= NUMKEYS) {
814 lastkey = 0;
815 }
816 }
817 }
818
819 check_updates(vs);
820}
821/*-----------------------------------------------------------------------------------*/
822void
823vnc_out_pointer_event(struct vnc_server_state *vs)
824{
825 struct rfb_pointer_event *ev;
826 u16_t evx, evy;
827
828 ev = (struct rfb_pointer_event *)uip_appdata;
829
830 evx = htons(ev->x);
831 evy = htons(ev->y);
832
833 if(evx > SCREEN_X && evx < SCREEN_WIDTH - 2 * SCREEN_X &&
834 evy > SCREEN_Y && evy < SCREEN_HEIGHT - 2 * SCREEN_Y) {
835
836 mouse_button = ev->buttonmask & RFB_BUTTON_MASK1;
837
838 mouse_x = evx - SCREEN_X;
839 mouse_y = evy - SCREEN_Y;
840
841 check_updates(vs);
842 }
843}
844/*-----------------------------------------------------------------------------------*/
845void
846vnc_out_acked(struct vnc_server_state *vs)
847{
848 if(vs->state != VNC_RUNNING) {
849 return;
850 }
851 if(vs->sendmsg == SENT_BLANK) {
852 init_send_screen(vs);
853 } else if(vs->sendmsg == SEND_BLANK) {
854 /* Do nothing until sendmsg == SENT_BLANK. */
855 } else if(vs->sendmsg == SEND_SCREEN) {
856 /* When the screen has been fully drawn, ->x2 and ->y2 are both
857 set to 0 to indicate this.*/
858 if(vs->x2 == 0 && vs->y2 == 0) {
859 vs->sendmsg = SEND_NONE;
860
861 /* If there was an updaterequest for the entire screen, we can
862 clear that flag now. */
863 if(vs->updates_current != NULL) {
864 vnc_server_update_free(vs, vs->updates_current);
865 vs->updates_current = NULL;
866 }
867 check_updates(vs);
868 } else {
869 vs->x1 = vs->x2;
870 vs->y1 = vs->y2;
871 }
872
873 } else if(vs->sendmsg == SEND_UPDATE) {
874 if(vs->x2 == 0 && vs->y2 == 0) {
875 /* So, we have updated the area that we needed. We now check if
876 there have been any recent full screen update requests. If
877 so, we need to go to the SEND_SCREEN state. Else, we see if
878 there were more areas that needed to be updated and if so,
879 we'll continue with those. */
880
881 vs->sendmsg = SEND_NONE;
882
883 if(vs->updates_current != NULL) {
884 vnc_server_update_free(vs, vs->updates_current);
885 vs->updates_current = NULL;
886
887 }
888 check_updates(vs);
889#if 0
890 if(vs->updaterequest == VNC_SERVER_UPDATE_FULL) {
891 check_updates(vs);
892 } else {
893 vs->updatesptr2 = (vs->updatesptr2 + 1) %
894 VNC_SERVER_MAX_UPDATES;
895
896 /* If there are no more updates to do, we'll go back to the
897 SEND_NONE state. */
898 if(vs->updatesptr2 == vs->updatesptr) {
899 vs->updatetype = VNC_SERVER_UPDATE_NONE;
900 } else {
901 /* Otherwise, we continue to update the next area. */
902 vs->updaterequest = VNC_SERVER_UPDATE_PARTS;
903 check_updates(vs);
904 }
905 }
906#endif /* 0 */
907 } else {
908 vs->x1 = vs->x2;
909 vs->y1 = vs->y2;
910 }
911 } else {
912 vs->sendmsg = SEND_NONE;
913 }
914}
915/*-----------------------------------------------------------------------------------*/
916void
917vnc_out_poll(struct vnc_server_state *vs)
918{
919 /* PRINTF(("vs->state %d, sendmsg %d, updatetype %d, updatereq %d\n",
920 vs->state, vs->sendmsg, vs->updatetype, vs->updaterequest);*/
921
922 if(vs->state == VNC_RUNNING &&
923 vs->sendmsg == SEND_NONE) {
924 check_updates(vs);
925 vnc_server_send_data(vs);
926 }
927}
928/*-----------------------------------------------------------------------------------*/
929void
930ctk_mouse_init(void)
931{
932
933}
934/*-----------------------------------------------------------------------------------*/
935unsigned short
936ctk_mouse_x(void)
937{
938 return mouse_x;
939}
940/*-----------------------------------------------------------------------------------*/
941unsigned short
942ctk_mouse_y(void)
943{
944 return mouse_y;
945}
946/*-----------------------------------------------------------------------------------*/
947unsigned char
948ctk_mouse_xtoc(unsigned short x)
949{
950 return x / FONT_WIDTH;
951}
952/*-----------------------------------------------------------------------------------*/
953unsigned char
954ctk_mouse_ytoc(unsigned short y)
955{
956 return y / FONT_HEIGHT;
957}
958/*-----------------------------------------------------------------------------------*/
959unsigned char
960ctk_mouse_button(void)
961{
962 return mouse_button;
963}
964/*-----------------------------------------------------------------------------------*/
965void
966ctk_mouse_hide(void)
967{
968}
969/*-----------------------------------------------------------------------------------*/
970void
971ctk_mouse_show(void)
972{
973}
974/*-----------------------------------------------------------------------------------*/