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