Contiki 2.6

vnc-out.c

00001 /*
00002  * Copyright (c) 2001, Adam Dunkels
00003  * All rights reserved. 
00004  *
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions 
00007  * are met: 
00008  * 1. Redistributions of source code must retain the above copyright 
00009  *    notice, this list of conditions and the following disclaimer. 
00010  * 2. Redistributions in binary form must reproduce the above copyright 
00011  *    notice, this list of conditions and the following disclaimer in the 
00012  *    documentation and/or other materials provided with the distribution. 
00013  * 3. The name of the author may not be used to endorse or promote
00014  *    products derived from this software without specific prior
00015  *    written permission.  
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00018  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00021  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00023  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00025  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00026  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
00028  *
00029  * This file is part of the uIP TCP/IP stack.
00030  *
00031  * $Id: vnc-out.c,v 1.3 2010/10/19 18:29:04 adamdunkels Exp $
00032  *
00033  */
00034 
00035 #include "contiki-net.h"
00036 #include "ctk/vnc-server.h"
00037 #include "ctk/vnc-out.h"
00038 #include "ctk/ctk-vncfont.h"
00039 
00040 #include "ctk/ctk-mouse.h"
00041 
00042 #include "lib/libconio.h"
00043 
00044 #ifdef WITH_AVR
00045 #include <avr/pgmspace.h>
00046 #else
00047 #define memcpy_P memcpy
00048 #endif /* WITH_AVR */
00049 
00050 #define CHARS_WIDTH    LIBCONIO_CONF_SCREEN_WIDTH
00051 #define CHARS_HEIGHT   LIBCONIO_CONF_SCREEN_HEIGHT
00052 
00053 #define SCREEN_X       10
00054 #define SCREEN_Y       8
00055 
00056 #define SCREEN_WIDTH  (CHARS_WIDTH * CTK_VNCFONT_WIDTH + 2 * SCREEN_X) /*420*/
00057 #define SCREEN_HEIGHT (CHARS_HEIGHT * CTK_VNCFONT_HEIGHT + 2 * SCREEN_Y) /*300*/
00058 #define BORDER_COLOR 0x00
00059 #define SCREEN_COLOR 0x00 /*0xc0*/
00060 
00061 #ifndef CH_HOME
00062 #define CH_HOME 0x50
00063 #endif 
00064 
00065 #ifndef CH_TAB
00066 #define CH_TAB  0x09
00067 #endif
00068 
00069 
00070 #define BGR(b,g,r) (((b) << 6) | (g) << 3 | (r))
00071 
00072 
00073 static const uint8_t menucolor[] = {
00074   BGR(3,7,7), /* Background. */           
00075   BGR(2,6,6), /* Anti-alias font color. */ 
00076   BGR(0,0,0), /* Font color. */            
00077 };
00078 
00079 
00080 static const uint8_t activemenucolor[] = {
00081   BGR(0,0,0), /* Background. */           
00082   BGR(2,5,5), /* Anti-alias font color. */ 
00083   BGR(3,7,7), /* Font color. */            
00084 };
00085 
00086 #define W  BGR(3,7,7)
00087 #define B  BGR(0,0,0)
00088 #define G0 BGR(0,2,2)
00089 #define G1 BGR(1,2,2)
00090 #define G2 BGR(1,3,3)
00091 #define G3 BGR(2,4,4)
00092 #define G4 BGR(2,5,5)
00093 #define G5 BGR(2,6,6)
00094 
00095 #define BG BGR(3,4,4)
00096 
00097 static const unsigned char backgroundcolor[] = {BG};
00098 
00099 static const unsigned char wincol[] =
00100   {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),G2,G3,G4};
00101   /*  {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),BGR(1,0,0),BGR(2,0,0),BGR(2,1,1)}; */
00102 static const unsigned char wincol_f[] =
00103   {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),G4,G5,W};
00104   /*  {BGR(3,7,7),BGR(1,2,2),BGR(0,1,1),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)}; */
00105 static const unsigned char wincol_d[] =
00106   {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)};
00107 
00108 static const unsigned char sepcol[] =
00109  {BGR(2,5,5),BGR(2,6,6),BGR(3,6,6)};
00110 static const unsigned char sepcol_f[] =
00111  {BGR(3,7,7),BGR(3,5,5),BGR(2,5,5)};
00112 static const unsigned char sepcol_d[] =
00113  {BGR(3,7,7),BGR(1,5,7),BGR(0,0,0)};
00114 
00115 static const unsigned char labcol[] =
00116  {BGR(2,5,5),BGR(1,3,3),BGR(0,1,1)};
00117 static const unsigned char labcol_f[] =
00118  {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0)};
00119 static const unsigned char labcol_d[] =
00120  {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0)};
00121 
00122 
00123 static const unsigned char butcol[] =
00124  {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
00125   BGR(2,5,5),BGR(2,5,5)};
00126 static const unsigned char butcol_w[] =
00127  {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
00128   BGR(2,5,5),BGR(2,5,5)};
00129 static const unsigned char butcol_f[] =
00130  {G5,G4,B,BGR(3,5,5),BGR(3,6,6),BGR(3,7,7),
00131   BGR(3,6,6),BGR(2,5,5)};
00132 static const unsigned char butcol_fw[] =
00133  {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0),BGR(1,3,3),BGR(2,7,7),BGR(3,7,7),
00134   BGR(3,6,6),BGR(3,7,7)};
00135 static const unsigned char butcol_d[] =
00136  {BGR(2,3,3),BGR(2,5,5),BGR(3,6,6),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
00137   BGR(3,7,7),BGR(2,5,5)};
00138 static const unsigned char butcol_dw[] =
00139  {BGR(0,0,0),BGR(2,5,5),BGR(3,7,7),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
00140   BGR(3,7,7),BGR(2,5,5)};
00141 
00142 
00143 static const unsigned char hlcol[] =
00144  {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
00145 static const unsigned char hlcol_w[] =
00146  {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
00147 static const unsigned char hlcol_f[] =
00148  {BGR(3,7,7),BGR(3,5,5),BGR(3,0,0)};
00149 static const unsigned char hlcol_fw[] =
00150  {BGR(3,7,7),BGR(3,6,7),BGR(3,7,7)};
00151 static const unsigned char hlcol_d[] =
00152  {BGR(3,7,7),BGR(3,5,5),BGR(2,0,0)};
00153 static const unsigned char hlcol_dw[] =
00154  {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
00155 
00156 static const unsigned char iconcol[] =
00157   {BG,G4,W,B,G1};
00158 static const unsigned char iconcol_w[] =
00159  {BGR(0,1,1),BGR(1,3,3),BGR(3,7,7), B,W};
00160 
00161 
00162 
00163 static const uint8_t * const colortheme[] =
00164   {
00165     backgroundcolor,
00166     
00167     /* Window colors */
00168     wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d,
00169 
00170     /* Separator colors. */
00171     sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d,    
00172 
00173     /* Label colors. */
00174     labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d,    
00175 
00176     /* Button colors. */
00177     butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,    
00178 
00179     /* Hyperlink colors. */
00180     hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw,
00181 
00182     /* Textentry colors. */
00183     butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
00184 
00185     /* Icon colors */
00186     iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w,
00187     
00188     /* Menu colors. */
00189     menucolor, activemenucolor, activemenucolor
00190   };
00191 
00192 
00193 static int mouse_x, mouse_y, mouse_button;
00194 
00195 #ifdef CTK_VNCSERVER_CONF_SCREEN
00196 static uint8_t *screen = CTK_VNCSERVER_CONF_SCREEN;
00197 #else
00198 static uint8_t screen[CHARS_WIDTH * CHARS_HEIGHT];
00199 #endif
00200 
00201 #ifdef CTK_VNCSERVER_CONF_COLORSCREEN
00202 staitc uint8_t *colorscreen = CTK_VNCSERVER_CONF_COLORSCREEN;
00203 #else
00204 static uint8_t colorscreen[CHARS_WIDTH * CHARS_HEIGHT];
00205 #endif
00206 
00207 
00208 #define PRINTF(x)
00209 
00210 /*-----------------------------------------------------------------------------------*/
00211 #define MAX_ICONS CTK_VNCSERVER_CONF_MAX_ICONS
00212 struct ctk_icon *icons[MAX_ICONS];
00213 
00214 unsigned char
00215 vnc_out_add_icon(struct ctk_icon *icon)
00216 {
00217   uint8_t i;
00218   signed int empty;
00219 
00220   empty = -1;
00221   for(i = 0; i < MAX_ICONS; ++i) {
00222     if(icon == icons[i]) {
00223       return i;
00224     }
00225     if(icons[i] == NULL && empty < 0){
00226       empty = i;
00227     }
00228   }
00229 
00230   if(empty == -1) {
00231     empty = 0;
00232   }
00233   icons[empty] = icon;
00234   return empty;
00235 }
00236 
00237 /*-----------------------------------------------------------------------------------*/
00238 void
00239 vnc_out_init(void)
00240 {
00241   uint16_t i;
00242   for(i = 0; i < CHARS_WIDTH * CHARS_HEIGHT; ++i) {
00243     screen[i] = 0x20;
00244   }
00245 }
00246 
00247 void
00248 vnc_out_update_screen(uint8_t xpos, uint8_t ypos, uint8_t c, uint8_t color)
00249 {
00250   screen[xpos + ypos * CHARS_WIDTH] = c;
00251   colorscreen[xpos + ypos * CHARS_WIDTH] = color;
00252 }
00253 /*-----------------------------------------------------------------------------------*/
00254 void
00255 vnc_out_update_area(struct vnc_server_state *vs,
00256                     uint8_t x, uint8_t y, uint8_t w, uint8_t h)
00257 {
00258   uint8_t x2, y2, ax2, ay2;
00259   register struct vnc_server_update *a, *b;
00260 
00261   PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
00262          x, y, w, h));
00263   
00264   /* First check if we already have a full update queued. If so, there
00265      is no need to put this update on the list. If there is a full
00266      update, it is always the first one on the list, so there is no
00267      need to go step the list in search for it. */
00268 
00269   if(vs->updates_pending != NULL &&
00270      vs->updates_pending->type == VNC_SERVER_UPDATE_FULL) {
00271     PRINTF(("Update_area_connecion: full update already queued...\n"));
00272     return;
00273   }
00274 
00275  again:
00276   
00277   /* Check that we don't update the same area twice by going through
00278      the list and search for an update with the same coordinates. */
00279   for(a = vs->updates_pending; a != NULL; a = a->next) {
00280     if(a->x == x && a->y == y &&
00281        a->w == w && a->h == h) {
00282       PRINTF(("Update_area_connecion: found equal area\n"));
00283       return;
00284     }    
00285   }
00286 
00287   /* Next we check if this update covers an existing update. If so, we
00288      remove the old update, expand this update so that it covers both
00289      areas to be updated and run through the process again. */
00290   b = NULL;
00291   for(a = vs->updates_pending; a != NULL; a = a->next) {      
00292     x2 = x + w;
00293     y2 = y + h;
00294     
00295     ax2 = a->x + a->w;
00296     ay2 = a->y + a->h;
00297 
00298     /* Test the corners of both updates to see if they are inside the
00299        other area. */
00300 #define INSIDE(x,y,x1,y1,x2,y2) ((x1) <= (x) && \
00301                                  (x2) >= (x) && \
00302                                  (y1) <= (y) && \
00303                                  (y2) >= (y))
00304     if(INSIDE(x, y, a->x, a->y, ax2, ay2) ||
00305        INSIDE(x, y2, a->x, a->y, ax2, ay2) ||
00306        INSIDE(x2, y2, a->x, a->y, ax2, ay2) ||
00307        INSIDE(x2, y, a->x, a->y, ax2, ay2) ||
00308        INSIDE(a->x, a->y, x, y, x2, y2) ||
00309        INSIDE(a->x, ay2, x, y, x2, y2) ||
00310        INSIDE(ax2, ay2, x, y, x2, y2) ||
00311        INSIDE(ax2, a->y, x, y, x2, y2)) {
00312 
00313       /* Remove the old update from the list. */
00314       vnc_server_update_remove(vs, a);
00315 
00316       /* Put it on the free list. */
00317       vnc_server_update_free(vs, a);
00318 
00319       PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
00320              a->x, a->y, ax2, ay2));
00321       
00322       /* Find the area that covers both updates. */
00323 #define MIN(a,b) ((a) < (b)? (a): (b))
00324 #define MAX(a,b) ((a) > (b)? (a): (b))
00325       x = MIN(a->x, x);
00326       y = MIN(a->y, y);
00327       ax2 = MAX(ax2, x2);
00328       ay2 = MAX(ay2, y2);
00329       w = ax2 - x;
00330       h = ay2 - y;
00331 
00332       /* This should really be done by a recursive call to this
00333          function: update_area_connection(vs, x, y, w, h); but because
00334          some compilers might not be able to optimize away the
00335          recursive call, we do it using a goto instead. */
00336       PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
00337       goto again;
00338     }
00339     if(b != NULL) {
00340       b = b->next;
00341     }
00342   }
00343   
00344   /* Allocate an update object by pulling it off the free list. If
00345      there are no free objects, we go for a full update instead. */
00346 
00347   /*  a = vs->updates_free;*/
00348   a = vnc_server_update_alloc(vs);
00349   if(a == NULL) {
00350     PRINTF(("Update_area_connecion: no free updates, doing full\n"));
00351     /* Put all pending updates, except for one, on the free list. Use
00352        the remaining update as a full update. */
00353     while(vs->updates_pending != NULL) {
00354       a = vs->updates_pending;
00355       vnc_server_update_remove(vs, a);
00356       vnc_server_update_free(vs, a);
00357     }
00358 
00359     a = vnc_server_update_alloc(vs);
00360     a->type = VNC_SERVER_UPDATE_FULL;
00361     vnc_server_update_add(vs, a);
00362                                         
00363 
00364   } else {
00365     
00366     PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
00367   /* Else, we put the update object at the end of the pending
00368      list. */
00369     a->type = VNC_SERVER_UPDATE_PARTS;
00370     a->x = x;
00371     a->y = y;
00372     a->w = w;
00373     a->h = h;
00374     vnc_server_update_add(vs, a);
00375   }
00376 }
00377 /*-----------------------------------------------------------------------------------*/
00378 static void
00379 init_send_screen(CC_REGISTER_ARG struct vnc_server_state *vs)
00380 {
00381   vs->sendmsg = SEND_SCREEN;
00382   vs->x = vs->y = 0;
00383   vs->x1 = vs->y1 = 0;
00384   vs->x2 = vs->y2 = 0;
00385   vs->w = CHARS_WIDTH;
00386   vs->h = CHARS_HEIGHT;
00387 }
00388 /*-----------------------------------------------------------------------------------*/
00389 static void
00390 check_updates(CC_REGISTER_ARG struct vnc_server_state *vs)
00391 {
00392   
00393   if(vs->state == VNC_RUNNING &&
00394      vs->sendmsg == SEND_NONE &&
00395      vs->updates_current == NULL) {
00396     if(vs->updates_pending != NULL &&
00397        vs->update_requested != 0) {
00398       vs->update_requested = 0;
00399       /*      vs->updates_current = vs->updates_pending;
00400       vs->updates_pending = vs->updates_pending->next;
00401       vs->updates_current->next = NULL;*/
00402 
00403       vs->updates_current = vnc_server_update_dequeue(vs);
00404       
00405       if(vs->updates_current->type == VNC_SERVER_UPDATE_PARTS) {
00406         vs->x = vs->x1 = vs->x2 = vs->updates_current->x;
00407         vs->y = vs->y1 = vs->y2 = vs->updates_current->y;
00408         vs->w = vs->updates_current->w;
00409         vs->h = vs->updates_current->h;
00410         vs->sendmsg = SEND_UPDATE;
00411         
00412         PRINTF(("New update from (%d:%d) (%d:%d) to (%d:%d)\n",
00413                vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
00414                vs->y + vs->h));
00415       } else if(vs->updates_current->type == VNC_SERVER_UPDATE_FULL) {
00416         init_send_screen(vs);
00417         PRINTF(("New full update\n"));
00418       }
00419     }
00420   }
00421 }
00422 /*-----------------------------------------------------------------------------------*/
00423 static uint8_t tmp[CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT];
00424 static void
00425 makechar(CC_REGISTER_ARG char *ptr, uint8_t x, uint8_t y)
00426 {
00427   uint8_t i, *tmpptr;
00428   register uint8_t *colorscheme;
00429   unsigned char *bitmap;
00430   uint8_t b, b2;
00431   uint8_t xmove, ymove;
00432   unsigned char c, color;
00433 
00434   color = colorscreen[x + y * CHARS_WIDTH];
00435   c = screen[x + y * CHARS_WIDTH];
00436 
00437   colorscheme = (uint8_t *)colortheme[color];
00438       
00439   /* First check if the character is a special icon character. These
00440      are to be interpreted in a special manner: the first character of
00441      the icon (the top left corner) has the highest bit set, but not
00442      bit 6. All other characters have bit 6 set, and also count the
00443      number of positions away from the top left corner. Only the top
00444      left corner contains enough information to identify the icon, all
00445      other chars only contain the number of steps to reach the
00446      identifying icon. */
00447   if((c & 0x80) != 0) {
00448     xmove = c & 0x0f;
00449     ymove = (c & 0x30) >> 4;
00450     
00451     c = colorscreen[x + y * CHARS_WIDTH];
00452 
00453     if(icons[c % MAX_ICONS] == NULL) {
00454       c = 0;
00455     }
00456     bitmap = icons[c % MAX_ICONS]->bitmap;
00457 
00458     if(bitmap != NULL) {
00459       bitmap = bitmap + ymove * 8*3;
00460       colorscheme = (uint8_t *)colortheme[VNC_OUT_ICONCOLOR + (c >> 6)];
00461       switch(xmove) {
00462       case 0:
00463         for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
00464           b = bitmap[i];
00465           *ptr++ = colorscheme[((b >> 7) & 0x01) << 2];
00466           *ptr++ = colorscheme[((b >> 6) & 0x01) << 2];
00467           *ptr++ = colorscheme[((b >> 5) & 0x01) << 2];
00468           *ptr++ = colorscheme[((b >> 4) & 0x01) << 2];
00469           *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
00470           *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];         
00471         }
00472         break;
00473       case 1:
00474         for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
00475           b = bitmap[i];
00476           b2 = bitmap[i + 8];
00477           *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
00478           *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
00479           *ptr++ = colorscheme[((b2 >> 7) & 0x01) << 2];
00480           *ptr++ = colorscheme[((b2 >> 6) & 0x01) << 2];
00481           *ptr++ = colorscheme[((b2 >> 5) & 0x01) << 2];
00482           *ptr++ = colorscheme[((b2 >> 4) & 0x01) << 2];                
00483         }
00484         break;
00485       case 2:
00486         for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
00487           b = bitmap[i + 8];
00488           b2 = bitmap[i + 16];
00489           *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
00490           *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
00491           *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
00492           *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];
00493           *ptr++ = colorscheme[((b2 >> 7) & 0x01) << 2];
00494           *ptr++ = colorscheme[((b2 >> 6) & 0x01) << 2];                
00495         }
00496         break;
00497       case 3:
00498         for(i = 0; i < CTK_VNCFONT_HEIGHT; ++i) {
00499           b = bitmap[i + 16];
00500           *ptr++ = colorscheme[((b >> 5) & 0x01) << 2];
00501           *ptr++ = colorscheme[((b >> 4) & 0x01) << 2];
00502           *ptr++ = colorscheme[((b >> 3) & 0x01) << 2];
00503           *ptr++ = colorscheme[((b >> 2) & 0x01) << 2];
00504           *ptr++ = colorscheme[((b >> 1) & 0x01) << 2];
00505           *ptr++ = colorscheme[((b >> 0) & 0x01) << 2];         
00506         }
00507         break;
00508       }
00509     }
00510   } else {
00511     memcpy_P(tmp, &ctk_vncfont[c * (CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT)],
00512              CTK_VNCFONT_WIDTH * CTK_VNCFONT_HEIGHT);
00513     
00514     tmpptr = tmp;
00515 
00516     
00517     for(i = 0; i < CTK_VNCFONT_HEIGHT * CTK_VNCFONT_WIDTH; ++i) {
00518       *ptr++ = colorscheme[*tmpptr++];
00519     }
00520   }
00521 }
00522 /*-----------------------------------------------------------------------------------*/
00523 void
00524 vnc_out_new(CC_REGISTER_ARG struct vnc_server_state *vs)
00525 {
00526   uint8_t i;
00527   
00528   vs->width = SCREEN_WIDTH;
00529   vs->height = SCREEN_HEIGHT;
00530   vs->x = vs->y = vs->x1 = vs->y1 = vs->x2 = vs->y2 = 0;
00531   vs->w = CHARS_WIDTH;
00532   vs->h = CHARS_HEIGHT;
00533 
00534   /* Initialize the linked list of updates. */
00535   for(i = 0; i < VNC_SERVER_MAX_UPDATES - 1; ++i) {
00536     vs->updates_pool[i].next = &vs->updates_pool[i + 1];    
00537   }
00538   vs->updates_pool[VNC_SERVER_MAX_UPDATES].next = NULL;
00539 
00540   vs->updates_free = &vs->updates_pool[0];
00541   vs->updates_pending = vs->updates_current = NULL;
00542 }
00543 /*-----------------------------------------------------------------------------------*/
00544 void
00545 vnc_out_send_blank(CC_REGISTER_ARG struct vnc_server_state *vs)
00546 {
00547   register struct rfb_fb_update *umsg;
00548   uint8_t *ptr;
00549   uint16_t len;
00550   uint8_t msglen;
00551       
00552   vs->x = vs->y = 0;
00553   vs->x2 = vs->y2 = 0;
00554           
00555   umsg = (struct rfb_fb_update *)uip_appdata;
00556   
00557   umsg->type = RFB_FB_UPDATE;
00558   umsg->rects = UIP_HTONS(2);
00559 
00560   ptr = (uint8_t *)umsg + sizeof(struct rfb_fb_update);
00561   len = sizeof(struct rfb_fb_update);
00562   
00563   msglen = vnc_server_draw_rect(ptr, 0, 0,
00564                                 UIP_HTONS(SCREEN_WIDTH),
00565                                 UIP_HTONS(SCREEN_HEIGHT),
00566                                 BORDER_COLOR);
00567 
00568   
00569   ptr += msglen;
00570   len += msglen;
00571 
00572   msglen = vnc_server_draw_rect(ptr,
00573                                 UIP_HTONS(SCREEN_X), UIP_HTONS(SCREEN_Y),
00574                                 UIP_HTONS(SCREEN_WIDTH - SCREEN_X * 2),
00575                                 UIP_HTONS(SCREEN_HEIGHT - SCREEN_Y * 2),
00576                                 SCREEN_COLOR);
00577 
00578   uip_send(uip_appdata, len + msglen);
00579 
00580   vs->sendmsg = SENT_BLANK;
00581 }
00582 /*-----------------------------------------------------------------------------------*/
00583 void
00584 vnc_out_send_screen(struct vnc_server_state *vs)
00585 {
00586   vnc_out_send_update(vs);
00587 }
00588 /*-----------------------------------------------------------------------------------*/
00589 static short tmpbuf[30];
00590 void
00591 vnc_out_send_update(CC_REGISTER_ARG struct vnc_server_state *vs)
00592 {
00593   uint8_t x, y, x0;
00594   uint8_t msglen;
00595   uint16_t len, n;
00596   uint8_t *ptr;
00597   struct rfb_fb_update *umsg;
00598   register struct rfb_fb_update_rect_hdr *recthdr;
00599   struct rfb_rre_hdr *rrehdr;
00600   uint8_t c, color, lastcolor;
00601   uint8_t numblanks;
00602 
00603   /* First, check if we need to feed the update function with a new
00604      pending update. */
00605   check_updates(vs);
00606 
00607   /*  PRINTF(("Sending Update from (%d:%d) (%d:%d) to (%d:%d)\n",
00608          vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
00609          vs->y + vs->h));*/
00610   
00611   umsg = (struct rfb_fb_update *)uip_appdata;
00612 
00613   umsg->type = RFB_FB_UPDATE;
00614 
00615   x0 = vs->x1;
00616   n = 0;
00617   msglen = 0;
00618   ptr = (uint8_t *)umsg + sizeof(struct rfb_fb_update);
00619   len = sizeof(struct rfb_fb_update);
00620   
00621   /* Loop over all characters that are covered by this update. */
00622   for(y = vs->y1; y < vs->y + vs->h; ++y) {
00623     for(x = x0; x < vs->x + vs->w; ++x) {
00624 
00625 
00626       /* First check if there are any blank space characters, and if
00627          so, find out how many of them there are in a row. Instead of
00628          sending the individual space characters as raw bitmaps, we
00629          can send the entire string of blanks as a single color
00630          rectangle instead. */
00631       
00632       c = screen[x + y * CHARS_WIDTH];
00633       numblanks = 0;
00634       lastcolor = color = colorscreen[x + y * CHARS_WIDTH];
00635 
00636       /* If the character is a blank, we continue reading characters
00637          until we find one that has a different color, or one that is
00638          not a blank. We must keep within the update rectangle, so we
00639          make sure that the "x" variable does not increase beyond the
00640          edge. The "numblanks" variable is used to keep track of how
00641          many blank characters we have found. */
00642       while(lastcolor == color &&
00643             c == 0x20 &&
00644             x < vs->x + vs->w) {
00645         ++numblanks;
00646 
00647         
00648         ++x;
00649         lastcolor = color;
00650         color = colorscreen[x + y * CHARS_WIDTH];
00651         c = screen[x + y * CHARS_WIDTH];
00652       }
00653 
00654       if(numblanks > 0) {
00655         
00656         /*      PRINTF(("Found %d blanks (%d:%d -> %d:%d)\n",
00657                 numblanks, x - numblanks, y, x, y));*/
00658         
00659         /* There were one or more blank characters, so we send out a
00660            single color rectangle with the right width. But first we
00661            make sure that there is enough space in the current TCP
00662            segment to put the rectangle. If there isn't we have to
00663            backtrack the "x" variable to where we found the first
00664            blank character so that the next TCP segment will be able
00665            to update this area instead. */      
00666 
00667         msglen = sizeof(struct rfb_fb_update_rect_hdr) +
00668           /*sizeof(struct rfb_rre_hdr)*/5;
00669 
00670         if(msglen >= uip_mss() - len) {
00671           /*      PRINTF(("Not enouch space for blanks (%d, left %d)\n",
00672                   msglen, uip_mss() - len));*/
00673           /* There is not enough space in the segment, so we remember
00674              where we were ... */
00675           vs->x2 = x - numblanks;
00676           vs->y2 = y;
00677 
00678           /* ... and we break out of the loop. */
00679           goto loopend;   
00680         }
00681 
00682         /* We construct a rectangle with the right width and color. */
00683         /*      recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
00684         recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
00685         rrehdr = (struct rfb_rre_hdr *)((char *)recthdr +
00686                  sizeof(struct rfb_fb_update_rect_hdr));
00687 
00688         /*      PRINTF(("Blankign (%d:%d) to (%d:%d)\n",
00689                (x - numblanks) * CTK_VNCFONT_WIDTH,
00690                y * CTK_VNCFONT_HEIGHT,
00691                CTK_VNCFONT_WIDTH * numblanks,
00692                CTK_VNCFONT_HEIGHT));*/
00693         recthdr->rect.x = uip_htons(SCREEN_X + (x - numblanks) *
00694                                 CTK_VNCFONT_WIDTH);
00695         recthdr->rect.y = uip_htons(SCREEN_Y + y * CTK_VNCFONT_HEIGHT);
00696         recthdr->rect.w = uip_htons(CTK_VNCFONT_WIDTH * numblanks);
00697         recthdr->rect.h = UIP_HTONS(CTK_VNCFONT_HEIGHT);
00698         recthdr->encoding[0] =
00699           recthdr->encoding[1] =
00700           recthdr->encoding[2] = 0;
00701         recthdr->encoding[3] = RFB_ENC_RRE;
00702         
00703         rrehdr->subrects[0] =
00704           rrehdr->subrects[1] = 0;
00705         rrehdr->bgpixel = colortheme[lastcolor][0];
00706 
00707         --x;
00708       } else {
00709 
00710         /* So there were no blank characters. */
00711 
00712         /*      PRINTF(("An char at (%d:%d)\n", x, y));*/
00713         /* First we must make sure that there is enough space in the
00714            outgoing TCP segment. */
00715 
00716         msglen = sizeof(struct rfb_fb_update_rect_hdr) +
00717           CTK_VNCFONT_HEIGHT * CTK_VNCFONT_WIDTH;
00718         if(msglen >= uip_mss() - len) {
00719           /*      PRINTF(("Not enouch space for char (%d, left %d)\n",
00720                   msglen, uip_mss() - len));*/
00721           
00722           /* There is not enough space in the segment, so we remember
00723              where we were ... */
00724           vs->x2 = x;
00725           vs->y2 = y;
00726 
00727           /* ... and we break out of the loop. */
00728           goto loopend;   
00729         }
00730 
00731         /*      PRINTF(("ptr %p\n",ptr);*/
00732         /*      recthdr = (struct rfb_fb_update_rect_hdr *)ptr;*/
00733         recthdr = (struct rfb_fb_update_rect_hdr *)tmpbuf;
00734 
00735         recthdr->rect.x = uip_htons(SCREEN_X + x * CTK_VNCFONT_WIDTH);
00736         recthdr->rect.y = uip_htons(SCREEN_Y + y * CTK_VNCFONT_HEIGHT);
00737         recthdr->rect.w = UIP_HTONS(CTK_VNCFONT_WIDTH);
00738         recthdr->rect.h = UIP_HTONS(CTK_VNCFONT_HEIGHT);
00739         recthdr->encoding[0] =
00740           recthdr->encoding[1] =
00741           recthdr->encoding[2] = 0;
00742         recthdr->encoding[3] = RFB_ENC_RAW;
00743 
00744         makechar((uint8_t *)recthdr +
00745                  sizeof(struct rfb_fb_update_rect_hdr),
00746                  x, y);
00747       }
00748       memcpy(ptr, tmpbuf, msglen);
00749       PRINTF(("Msglen %d (%d:%d)\n", msglen, x, y));
00750       len += msglen;
00751       ptr += msglen;
00752       ++n;
00753     }
00754     x0 = vs->x;
00755   }
00756   
00757  loopend:
00758 
00759   umsg->rects = uip_htons(n);
00760         
00761   if(y == vs->y + vs->h && x == vs->x + vs->w) {
00762     vs->x2 = vs->y2 = 0;
00763   }
00764 
00765   if(n > 0) {
00766     /*    printf("Sending %d rects, %d bytes (%p, %p, %p)\n", n, len,
00767           uip_appdata, umsg, ptr);*/
00768     uip_send(uip_appdata, len);
00769   }
00770 
00771 }
00772 /*-----------------------------------------------------------------------------------*/
00773 #define NUMKEYS 20
00774 static char keys[NUMKEYS];
00775 static int firstkey, lastkey;
00776 
00777 
00778 char
00779 vnc_out_keyavail(void)
00780 {
00781   return firstkey != lastkey;
00782 }
00783 
00784 char
00785 vnc_out_getkey(void)
00786 {
00787   char key;
00788   key = keys[firstkey];
00789   
00790   if(firstkey != lastkey) {
00791     ++firstkey;
00792     if(firstkey >= NUMKEYS) {
00793       firstkey = 0;
00794     }
00795   }
00796   
00797   return key;  
00798 }
00799 
00800 void
00801 vnc_out_key_event(struct vnc_server_state *vs)
00802 {
00803   register struct rfb_key_event *ev;
00804   
00805   ev = (struct rfb_key_event *)uip_appdata;
00806 
00807   if(ev->down != 0) {
00808     if(vs->sendmsg == SEND_NONE) {
00809       vs->sendmsg = SEND_UPDATE;
00810     }
00811 
00812 
00813     if(ev->key[2] == 0 ||
00814        (ev->key[2] == 0xff &&   
00815         (ev->key[3] == CH_HOME ||
00816          ev->key[3] == CH_TAB ||
00817          ev->key[3] == CH_ESC ||
00818          ev->key[3] == CH_DEL ||
00819          ev->key[3] == CH_ENTER ||
00820          ev->key[3] == CH_CURS_LEFT ||
00821          ev->key[3] == CH_CURS_UP ||
00822          ev->key[3] == CH_CURS_RIGHT ||
00823          ev->key[3] == CH_CURS_DOWN))) {
00824       
00825       keys[lastkey] = ev->key[3];
00826       ++lastkey;
00827       if(lastkey >= NUMKEYS) {
00828         lastkey = 0;
00829       }
00830     }
00831   }
00832 
00833   check_updates(vs);
00834 }
00835 /*-----------------------------------------------------------------------------------*/
00836 void
00837 vnc_out_pointer_event(struct vnc_server_state *vs)
00838 {
00839   struct rfb_pointer_event *ev;
00840   uint16_t evx, evy;
00841   
00842   ev = (struct rfb_pointer_event *)uip_appdata;
00843 
00844   evx = uip_htons(ev->x);
00845   evy = uip_htons(ev->y);
00846   
00847   if(evx > SCREEN_X && evx < SCREEN_WIDTH - 2 * SCREEN_X &&
00848      evy > SCREEN_Y && evy < SCREEN_HEIGHT - 2 * SCREEN_Y) {
00849 
00850     mouse_button = ev->buttonmask & RFB_BUTTON_MASK1;
00851     
00852     mouse_x = evx - SCREEN_X;
00853     mouse_y = evy - SCREEN_Y;
00854 
00855     check_updates(vs);    
00856   }    
00857 }
00858 /*-----------------------------------------------------------------------------------*/
00859 void
00860 vnc_out_acked(CC_REGISTER_ARG struct vnc_server_state *vs)
00861 {
00862   if(vs->state != VNC_RUNNING) {
00863     return;
00864   }
00865   if(vs->sendmsg == SENT_BLANK) {
00866     init_send_screen(vs);
00867   } else if(vs->sendmsg == SEND_BLANK) {
00868     /* Do nothing until sendmsg == SENT_BLANK. */
00869   } else if(vs->sendmsg == SEND_SCREEN) {
00870     /* When the screen has been fully drawn, ->x2 and ->y2 are both
00871        set to 0 to indicate this.*/
00872     if(vs->x2 == 0 && vs->y2 == 0) {
00873       vs->sendmsg = SEND_NONE;
00874       
00875       /* If there was an updaterequest for the entire screen, we can
00876          clear that flag now. */
00877       if(vs->updates_current != NULL) { 
00878         vnc_server_update_free(vs, vs->updates_current);
00879         vs->updates_current = NULL;
00880       }
00881       check_updates(vs);
00882     } else {
00883       vs->x1 = vs->x2;
00884       vs->y1 = vs->y2;
00885     }
00886               
00887   } else if(vs->sendmsg == SEND_UPDATE) {
00888     if(vs->x2 == 0 && vs->y2 == 0) {
00889       /* So, we have updated the area that we needed. We now check if
00890          there have been any recent full screen update requests. If
00891          so, we need to go to the SEND_SCREEN state. Else, we see if
00892          there were more areas that needed to be updated and if so,
00893          we'll continue with those. */
00894 
00895       vs->sendmsg = SEND_NONE;
00896 
00897       if(vs->updates_current != NULL) {
00898         vnc_server_update_free(vs, vs->updates_current);
00899         vs->updates_current = NULL;
00900 
00901       }
00902       check_updates(vs);
00903 #if 0
00904       if(vs->updaterequest == VNC_SERVER_UPDATE_FULL) {
00905         check_updates(vs);
00906       } else {
00907         vs->updatesptr2 = (vs->updatesptr2 + 1) %
00908           VNC_SERVER_MAX_UPDATES;
00909 
00910         /* If there are no more updates to do, we'll go back to the
00911            SEND_NONE state. */  
00912         if(vs->updatesptr2 == vs->updatesptr) {
00913           vs->updatetype = VNC_SERVER_UPDATE_NONE;
00914         } else {         
00915           /* Otherwise, we continue to update the next area. */
00916           vs->updaterequest = VNC_SERVER_UPDATE_PARTS;
00917           check_updates(vs);
00918         }
00919       }
00920 #endif /* 0 */
00921     } else {         
00922       vs->x1 = vs->x2;
00923       vs->y1 = vs->y2;
00924     }    
00925   } else {
00926     vs->sendmsg = SEND_NONE;
00927   }
00928 }
00929 /*-----------------------------------------------------------------------------------*/
00930 void
00931 vnc_out_poll(struct vnc_server_state *vs)
00932 {
00933   /*  PRINTF(("vs->state %d, sendmsg %d, updatetype %d, updatereq %d\n",
00934       vs->state, vs->sendmsg, vs->updatetype, vs->updaterequest);*/
00935   
00936   if(vs->state == VNC_RUNNING &&
00937      vs->sendmsg == SEND_NONE) {
00938     check_updates(vs);
00939     vnc_server_send_data(vs);
00940   }
00941 }
00942 /*-----------------------------------------------------------------------------------*/
00943 #if CTK_CONF_MOUSE_SUPPORT
00944 void
00945 ctk_mouse_init(void)
00946 {
00947 
00948 }
00949 /*-----------------------------------------------------------------------------------*/
00950 unsigned short
00951 ctk_mouse_x(void)
00952 {
00953   return mouse_x;
00954 }
00955 /*-----------------------------------------------------------------------------------*/
00956 unsigned short
00957 ctk_mouse_y(void)
00958 {
00959   return mouse_y;
00960 }
00961 /*-----------------------------------------------------------------------------------*/
00962 unsigned char
00963 ctk_mouse_button(void)
00964 {
00965   return mouse_button;
00966 }
00967 /*-----------------------------------------------------------------------------------*/
00968 void
00969 ctk_mouse_hide(void)
00970 {
00971 }
00972 /*-----------------------------------------------------------------------------------*/
00973 void
00974 ctk_mouse_show(void)
00975 {
00976 }
00977 /*-----------------------------------------------------------------------------------*/
00978 #endif /* CTK_CONF_MOUSE_SUPPORT */