📄 vnc-server.c
字号:
/*****************************************************************************/
/** Frame update thread.
*
* @param data Ignored
*
* This thread handles the sending of all frame update data to the client and
* sends the 'ring bell' message to the client when required.
*
*****************************************************************************/
#ifdef CYGPKG_NET
void frame_update(cyg_addrword_t data)
#else
static void frame_update(void *data)
#endif
{
int i, j;
int x_pos, y_pos;
int packet_length;
int num_updated_tiles;
cyg_uint16 *ptr_to_uint16;
static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
/* These are declared static so they don't use thread stack memory */
static cyg_uint8 FramebufferUpdate_msg[4 + 12 + TILE_SIZE*TILE_SIZE*BITS_PER_PIXEL/8 + 1460];
static int FrameBufferPtr; /* Pointer to next space in buffer */
static int tile_updated_local[NUM_TILES_Y_AXIS][NUM_TILES_X_AXIS];
while(1)
{
/* Wait until client sends a frame update request */
wait_for_client:
cyg_mutex_lock(&client_active_lock); /* Lock the mutex */
while( update_req == 0 ) /* Wait until the client is active */
{
cyg_cond_wait(&client_active_wait);
}
cyg_mutex_unlock(&client_active_lock);
/* Copy tile_updated array to local version and clear copied tiles */
cyg_scheduler_lock();
num_updated_tiles = 0;
for (i = 0; i < NUM_TILES_Y_AXIS; i++)
{
for (j = 0; j < NUM_TILES_X_AXIS; j++)
{
if (tile_updated[i][j])
{
tile_updated_local[i][j] = 1;
tile_updated[i][j] = 0;
num_updated_tiles++; /* Keep count of the updated tiles */
}
}
}
cyg_scheduler_unlock();
if (num_updated_tiles)
{
/* Fill in constant parts of FramebufferUpdate Message */
FramebufferUpdate_msg[0] = 0; /* Message-type */
FramebufferUpdate_msg[1] = 0; /* Padding */
ptr_to_uint16 = (cyg_uint16 *) &(FramebufferUpdate_msg[2]);
*ptr_to_uint16 = htons(num_updated_tiles); /* Number-of-rectangles */
FrameBufferPtr = 4;
for (y_pos = 0; y_pos < NUM_TILES_Y_AXIS; y_pos++)
{
for (x_pos = 0; x_pos < NUM_TILES_X_AXIS; x_pos++)
{
if (tile_updated_local[y_pos][x_pos])
{
if (update_req)
{
cyg_mutex_lock(&client_active_lock); /* Lock the mutex */
update_req = 0; /* Cancel the update request flag */
cyg_mutex_unlock(&client_active_lock); /* Unlock the mutex */
}
/* Send current square data to client */
/* x-position */
FramebufferUpdate_msg[FrameBufferPtr+0] = (x_pos * TILE_SIZE) / 256;
FramebufferUpdate_msg[FrameBufferPtr+1] = (x_pos * TILE_SIZE) % 256;
/* y-position */
FramebufferUpdate_msg[FrameBufferPtr+2] = (y_pos * TILE_SIZE) / 256;
FramebufferUpdate_msg[FrameBufferPtr+3] = (y_pos * TILE_SIZE) % 256;
/* Set width of tile in packet */
if (x_pos == (NUM_TILES_X_AXIS -1))
{
/* Last tile in X-axis */
FramebufferUpdate_msg[FrameBufferPtr+4] = LAST_TILE_WIDTH / 256;
FramebufferUpdate_msg[FrameBufferPtr+5] = LAST_TILE_WIDTH % 256;
}
else
{
FramebufferUpdate_msg[FrameBufferPtr+4] = TILE_SIZE / 256;
FramebufferUpdate_msg[FrameBufferPtr+5] = TILE_SIZE % 256;
}
if (y_pos == (NUM_TILES_Y_AXIS -1))
{
/* Last tile in Y-axis */
FramebufferUpdate_msg[FrameBufferPtr+6] = LAST_TILE_HEIGHT / 256;
FramebufferUpdate_msg[FrameBufferPtr+7] = LAST_TILE_HEIGHT % 256;
}
else
{
FramebufferUpdate_msg[FrameBufferPtr+6] = TILE_SIZE / 256;
FramebufferUpdate_msg[FrameBufferPtr+7] = TILE_SIZE % 256;
}
/* Generate the packet data for this tile */
packet_length = GenTileUpdateData(&(FramebufferUpdate_msg[FrameBufferPtr]));
/* Send the packet data for this tile to the client */
FrameBufferPtr += packet_length;
if (FrameBufferPtr > 1460)
{
/* Send the data to the client */
if (send(client_sock, FramebufferUpdate_msg, FrameBufferPtr, 0) != FrameBufferPtr)
{
goto wait_for_client;
}
FrameBufferPtr = 0;
}
tile_updated_local[y_pos][x_pos] = 0; /* Clear the update bit for this square */
}
}
}
if (FrameBufferPtr > 0)
{
/* Last data for this update, send it to the client */
if (send(client_sock, FramebufferUpdate_msg, FrameBufferPtr, 0) != FrameBufferPtr)
{
goto wait_for_client;
}
FrameBufferPtr = 0;
}
}
else /* if (num_updated_tiles) */
{
/* There was no new display data to send to the client */
/* Sleep for 1/20th second before checking again */
cyg_thread_delay(rtc_resolution[1]/20);
}
/* Check for sound bell event */
cyg_mutex_lock(&SoundBell_lock);
if (SoundBellCount)
{
--SoundBellCount;
cyg_mutex_unlock(&SoundBell_lock);
if (send(client_sock, sound_bell, 1, 0) != 1)
{
goto wait_for_client;
}
}
else
{
cyg_mutex_unlock(&SoundBell_lock);
}
}
}
/*****************************************************************************/
/** Generate tile update data function
*
* @param *packet_buffer Buffer to store tile data
*
* @return Length of generated data in bytes
*
* This function is called by the frame_update thread to generate the message
* data for a tile to send to the client. This function expects the
* x-position, y-position, width and height fields of the buffer to be filled
* in before it is called.
*
* The format of the buffer is:
* packet_buffer[0:1] - x-position of tile
* packet_buffer[2:3] - y-position of tile
* packet_buffer[4:5] - width of tile
* packet_buffer[6:7] - height of tile
* packet_buffer[8 onwards] - Pixel data for the tile
*
* The pixel data will be encoded with CoRRE encoding (if the CDL option is
* enabled and the client can handle it) or RAW encoding if that is smaller
* than CoRRE encoding for that particular tile.
*
*****************************************************************************/
static int GenTileUpdateData(cyg_uint8 *packet_buffer)
{
cyg_uint16 x_pos, y_pos;
int i, j;
int packet_length;
int tile_width, tile_height;
#ifdef CYGNUM_VNC_SERVER_USE_CORRE_ENCODING
static vnc_colour_t tile_buffer[TILE_SIZE][TILE_SIZE]; /* Buffer to hold tile to be encoded */
vnc_colour_t pixel_colour;
vnc_colour_t bg_colour;
int no_of_subrects, subrect_width, subrect_height;
int k, l;
no_of_subrects = 0; /* Set to no sub-rectangles to start with */
#endif /* CYGNUM_VNC_SERVER_USE_CORRE_ENCODING */
packet_length = 20-4+(BITS_PER_PIXEL/8); /* Set to minimum packet length to start with */
/* Get the X and Y positions of this tile from the packet buffer */
x_pos = packet_buffer[0] * 256 + packet_buffer[1];
y_pos = packet_buffer[2] * 256 + packet_buffer[3];
/* Get the tile width and height from the packet buffer */
tile_width = packet_buffer[4] * 256 + packet_buffer[5];
tile_height = packet_buffer[6] * 256 + packet_buffer[7];
#ifdef CYGNUM_VNC_SERVER_USE_CORRE_ENCODING
/* Set the encoding type to RRE */
if (!encoding_type.corre)
{
/* CoRRE encoding is not supported - just use raw encoding */
goto use_raw_encoding;
}
/* Set encoding type to CoRRE encoding in packet buffer */
packet_buffer[8+0] = 0;
packet_buffer[8+1] = 0;
packet_buffer[8+2] = 0;
packet_buffer[8+3] = 4;
/* Copy tile from the main frame buffer to the local tile buffer */
for (i = 0; i < tile_height; i++)
{
for (j = 0; j < tile_width; j++)
{
tile_buffer[i][j] = frame_buffer[y_pos + i][x_pos + j];
}
}
/* Find the background colour */
/* We just assume the (0, 0) pixel in the tile is the bgcolour */
/* Its quick!!! */
bg_colour = frame_buffer[y_pos][x_pos];
/* Set the background colour in the packet buffer */
#if BITS_PER_PIXEL == 8
packet_buffer[16] = (vnc_colour_t) bg_colour;
#endif
#if BITS_PER_PIXEL == 16
packet_buffer[16] = COLOUR2BYTE0(bg_colour);
packet_buffer[16+1] = COLOUR2BYTE1(bg_colour);
#endif
#ifdef CYGNUM_VNC_SERVER_CORRE_ENCODING_HACK
/* Add an initial sub-rectangle to paint the background the background colour */
/* This is required because of a known bug in the VNC viewer (x86 version) */
#if BITS_PER_PIXEL == 8
packet_buffer[packet_length] = (vnc_colour_t) bg_colour;
packet_length++;
#endif
#if BITS_PER_PIXEL == 16
packet_buffer[packet_length] = packet_buffer[16];
packet_buffer[packet_length+1] = packet_buffer[16+1];
packet_length += 2;
#endif
packet_buffer[packet_length] = (cyg_uint8) 0; /* Sub-rect x-pos */
packet_buffer[packet_length+1] = (cyg_uint8) 0; /* Sub-rect y-pos*/
packet_buffer[packet_length+2] = (cyg_uint8) tile_width; /* Sub-rect width*/
packet_buffer[packet_length+3] = (cyg_uint8) tile_height; /* Sub-rect height*/
packet_length += 4;
no_of_subrects++; /* Increment sub-rectangle count */
#endif
/* Scan trough tile and find sub-rectangles */
for (i = 0; i < tile_height; i++)
{
for (j = 0; j < tile_width; j++)
{
if (tile_buffer[i][j] != bg_colour)
{
/* This is a non-background pixel */
subrect_width = 1;
pixel_colour = tile_buffer[i][j];
/* Extend the sub-rectangle to its maximum width */
for (subrect_width = 1; subrect_width <= tile_width-j-1; subrect_width++)
{
if (tile_buffer[i][j+subrect_width] != pixel_colour)
{
goto got_subrect_width;
}
}
got_subrect_width:
/* Extend the sub-rectangle to its maximum height */
for (subrect_height=1; subrect_height <= tile_height-i-1; subrect_height++)
{
for (k = j; k < j+subrect_width; k++)
{
if (tile_buffer[i+subrect_height][k] != pixel_colour)
{
goto got_subrect_height;
}
}
}
got_subrect_height:
/* Delete the pixels for the sub-rectangle from the sub-rectangle */
for (k = i; k < i+subrect_height; k++)
{
for (l = j; l < j+subrect_width; l++)
{
tile_buffer[k][l] = bg_colour;
}
}
/* Append new sub-rectangle data to the packet buffer */
#if BITS_PER_PIXEL == 8
packet_buffer[packet_length] = (vnc_colour_t) pixel_colour;
packet_length++;
#endif
#if BITS_PER_PIXEL == 16
packet_buffer[packet_length] = COLOUR2BYTE0(pixel_colour);
packet_buffer[packet_length+1] = COLOUR2BYTE1(pixel_colour);
packet_length += 2;
#endif
packet_buffer[packet_length] = (cyg_uint8) j; /* Sub-rect x-pos */
packet_length++;
packet_buffer[packet_length] = (cyg_uint8) i; /* Sub-rect y-pos*/
packet_length++;
packet_buffer[packet_length] = (cyg_uint8) subrect_width; /* Sub-rect width*/
packet_length++;
packet_buffer[packet_length] = (cyg_uint8) subrect_height; /* Sub-rect height*/
packet_length++;
no_of_subrects++; /* Increment sub-rectangle count */
if (packet_length >= 12 + tile_height*tile_width*(BITS_PER_PIXEL/8) - 6)
{
/* The next sub-rectangle will make the packet size */
/* larger than a rew encoded packet - so just use raw */
goto use_raw_encoding;
}
}
}
}
/* Fill in no_of_sub-rectangles field in packet buffer */
packet_buffer[12+0] = 0;
packet_buffer[12+1] = 0;
packet_buffer[12+2] = no_of_subrects / 256;
packet_buffer[12+3] = no_of_subrects % 256;
/* CoRRE data encoding for tile complete */
return packet_length;
use_raw_encoding:
#endif /* CYGNUM_VNC_SERVER_USE_CORRE_ENCODING */
/* Create packet data using RAW encoding */
for (i = 0; i < tile_height; i++)
{
for (j = 0; j < tile_width; j++)
{
#if BITS_PER_PIXEL == 8
packet_buffer[12 + tile_width * i + j] = frame_buffer[y_pos + i][x_pos + j];
#endif
#if BITS_PER_PIXEL == 16
packet_buffer[12 + 2 * tile_width * i + 2*j] = COLOUR2BYTE0(frame_buffer[y_pos + i][x_pos + j]);
packet_buffer[12 + 2 * tile_width * i + 2*j+ 1] = COLOUR2BYTE1(frame_buffer[y_pos + i][x_pos + j]);
#endif
}
}
/* Set the encoding type to raw */
packet_buffer[8+0] = 0;
packet_buffer[8+1] = 0;
packet_buffer[8+2] = 0;
packet_buffer[8+3] = 0;
return (12 + tile_width*tile_height*(BITS_PER_PIXEL/8));
}
/*****************************************************************************/
/** Get message data function
*
* @param socket_fd File descriptor of the socket to get the data from.
* @param *buffer Buffer to store received data in.
* @param num_bytes Number of bytes to attempt to get.
*
* @return 1 on sucessfull completion - 0 on error.
*
* This function is called by the client_handler thread to get data from the
* client's socket.
*
*****************************************************************************/
static int GetMessageData(int socket_fd, char *buffer, int num_bytes)
{
int bytes_rxd;
int message_len = 0;
while (message_len < num_bytes)
{
if ((bytes_rxd = recv(socket_fd, buffer, num_bytes, 0)) <= 0)
{
return 0;
}
message_len += bytes_rxd;
}
return 1;
}
/* Driver functions */
vnc_frame_format_t* VncGetInfo(void)
{
return &frame_format;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -