Contiki 2.6
|
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 */