Subject: early 32bit hextile support!
From: bob hawbaker (bhawbaker@uswest.net)
Date: Sun Sep 24 2000 - 15:42:20 MDT
i got tired of the raw-encoding only support in the mol's vnc code so
i decided to do a quick-n-dirty code to get the hextile in..
currently it supports only 32bit.. i tested it only with 1024x768..
using it at 16bit (15bit) results in garbage screen and mabye vnc
thread hanging...
nevertheless, i am sure that someone out there really want hextile
*NOW* like i did and don't mind the only 32bit limitation :) so
here is the new vncvideo.c. i used the hextile code from
vnc_unixsrc.. maybe someone can fix the <32bit problem.. no copyrect
support, sorry.. mol returns only line by line changes so can't do
rect at this time.
bob
------ vncvideo.c
/*
* Copyright (C) 1999, 2000 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
/*
* vncvideo.c - a driver for mol which exports the display via the VNC protocol
*
* This pretty much a hack. There are lots of things done very inelegantly
* and sometimes just plain wrong. Do not be surprised if it doesn't work.
*
* To enable this driver put enable_vncvideo in your molrc.
*
* To specifiy which port to use to serve VNC add a line like this:
*
* vnc_port: 5900
*
* If you don't specifiy vnc_port you'll get a random one (probably)
*
* It serve unauthenticated VNC (i.e. anyone with access to your vnc
port has ac
* ess to MOL). There is no http server (yet) so java connections won't work.
*
* CREDITS:
* Christian Bauer - original Basillisk II X-driver
* Samuel Rydh - original xvideo driver and, of course, MOL.
* Tristan Richardson - VNC
* Nick Hollighurst - Linux hackery
*
* AUTHOR:
* Charlie McLachlan cim@uk.research.att.com
*
* FURTHER DETAILS:
* http://www.uk.research.att.com/vnc
* http://www.ibrium.se
*
* VERSION:
* 0.0.0 - 8 May 2000
*
*/
#include "mol_config.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XShm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <pthread.h>
#include <errno.h>
#include <driver_mgr.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include "verbose.h"
#include "debugger.h"
#include "res_manager.h"
#include "memory.h"
#include "mouse_sh.h"
#include "wrapper.h"
#include "thread.h"
#include "video.h"
#include "adb.h"
// --- Basic VNC definitions -----
typedef unsigned char CARD8;
typedef unsigned short CARD16;
typedef unsigned int CARD32;
#include "rfbproto.h"
// --- Mol definitions ----------
SET_VERBOSE_NAME("vncvideo");
typedef unsigned char uint8;
typedef int bool;
#define false 0
#define true 1
#define ADBKeyDown( ch ) adb_key( (ch & 0x7f) );
#define ADBKeyUp( ch ) adb_key( (ch | 0x80) );
// ---- vnc helper macros ----------
#define CARD32IntoCARD8Star(a, b) \
*(b++) = ((a) & 0xff000000) >> 24; \
*(b++) = ((a) & 0xff0000) >> 16; \
*(b++) = ((a) & 0xff00) >> 8; \
*(b++) = ((a) & 0xff);
#define SwapCARD32IntoCARD8Star(a, b) \
*(b++) = ((a) & 0xff); \
*(b++) = ((a) & 0xff00) >> 8; \
*(b++) = ((a) & 0xff0000) >> 16; \
*(b++) = ((a) & 0xff000000) >> 24;
#define CARD16IntoCARD8Star(a, b) \
*(b++) = ((a) & 0xff00) >> 8; \
*(b++) = ((a) & 0xff);
#define SwapCARD16IntoCARD8Star(a, b) \
*(b++) = ((a) & 0xff); \
*(b++) = ((a) & 0xff00) >> 8;
#define IndexedToRemote(i) \
((mac_pal[i*3] * remote_format.redMax + 127) / 255) \
<< remote_format.redShift | \
((mac_pal[i*3 + 1] * remote_format.greenMax + 127) / 255) \
<< remote_format.greenShift | \
((mac_pal[i*3 + 2] * remote_format.blueMax + 127) / 255) \
<< remote_format.blueShift;
#define RGB555ToRemote(i) \
(((((i >> 10) & 31) * remote_format.redMax + 15) / 31) \
<< remote_format.redShift) | \
(((((i >> 5) & 31) * remote_format.greenMax + 15) / 31) \
<< remote_format.greenShift) | \
((((i & 31) * remote_format.blueMax + 15) / 31) \
<< remote_format.blueShift);
#define RGB565ToRemote(i) \
(((((i >> 11) & 31) * remote_format.redMax + 15) / 31) \
<< remote_format.redShift) | \
(((((i >> 5) & 63) * remote_format.greenMax + 31) / 63) \
<< remote_format.greenShift) | \
((((i & 31) * remote_format.blueMax + 15) / 31) \
<< remote_format.blueShift);
/* #define RGB888ToRemote(i) \
(((((i >> 16) & 0xff) * remote_format.redMax + 127) / 255) \
<< remote_format.redShift) | \
(((((i >> 8) & 0xff) * remote_format.greenMax + 127) / 255) \
<< remote_format.greenShift) | \
((((i & 0xff) * remote_format.blueMax + 127) / 255) \
<< remote_format.blueShift); */
#define ARGB8888ToRemote(i) \
(((((i >> 16) & 0xff) * remote_format.redMax + 127) / 255) \
<< remote_format.redShift) | \
(((((i >> 8) & 0xff) * remote_format.greenMax + 127) / 255) \
<< remote_format.greenShift) | \
((((i & 0xff) * remote_format.blueMax + 127) / 255) \
<< remote_format.blueShift);
// --- Functions called by Mol via the module interface ----
static int vnc_init( video_module_t *mod );
static void vnc_cleanup( video_module_t *mod );
static int vopen( video_desc_t *mode );
static void vclose( void );
static void vrefresh( void );
static void setcmap(char *pal);
static bool sendHextiles8( int x, int y, int w, int h);
static bool sendHextiles16( int x, int y, int w, int h);
static bool sendHextiles32( int x, int y, int w, int h);
video_module_t vnc_module = {
"vnc", vnc_init, vnc_cleanup, vopen,
vclose, vrefresh, setcmap,
NULL, NULL
};
// cache the Mac's palette
static unsigned char mac_pal[256 * 3];
// bpp = bytes per pixel
static int offscreen_bpp = 2;
static int output_bpp = 2;
// --- vnc functions -------------------------------
// the main thread. This calls the others
static void vnc_func(void *arg);
static void send_update();
static void translate(unsigned char *in, unsigned char *out, int pixels);
static bool send_rect(int x, int y, int w, int h);
static int ks_decode(CARD32 ks);
static bool request_received = false;
static volatile int vnc_sock = -1;
static bool vnc_sock_valid = true;
bool read_exact(unsigned char *buffer, int size);
bool write_exact(const unsigned char *buffer, int size);
static rfbPixelFormat remote_format;
// --- listen thread -------------
static void listen_func(void *arg);
// --- vnc thread / main communication
static bool force_redraw = false;
static bool is_open = false;
static unsigned char *offscreen_buf = NULL; // The Mac's Buffer
static unsigned char *output_buf = NULL;
static long output_buf_size = 0;
static pthread_mutex_t buffers_mutex = PTHREAD_MUTEX_INITIALIZER;
static video_desc_t vmode; // format of the Mac's buffer
static bool connection_running = false; // is anyone connected?
static void init_translationtable();
static volatile CARD8 translationtable[65536 * 4];
// --- listen / main communication
static volatile bool listener_must_die = false;
static bool g_CanHextile = false;
/* ***************************************************************
Main thread (module entry points)
*************************************************************** */
static int vnc_init( video_module_t *m )
{
const int depths[] = { 8, 16, 24, 32 };
video_desc_t *vm;
int i;
LOG( "vnc_init called\n" );
if( get_bool_res("enable_vncvideo")!=1 )
return 1;
vm = calloc( 4, sizeof( video_desc_t ));
vnc_module.modes = vm;
for(i=0; i<4; i++ ){
vm[i].offs = -1;
vm[i].rowbytes = -1;
vm[i].h = -1;
vm[i].w = -1;
vm[i].depth = depths[i];
vm[i].next = (i+1<4) ? &vm[i+1] : NULL;
}
is_open = false;
// start a listening thread
create_thread( listen_func, NULL, "VNC-Listener");
return 0;
}
static void vnc_cleanup(video_module_t *m )
{
int k = 0;
struct sockaddr_in self;
int self_socket = socket(AF_INET, SOCK_STREAM, 0);
int addrlen = sizeof(self);
LOG("vnc_cleanup called\n");
if (vnc_sock != -1)
{
LOG("Shutting down vnc sock\n");
// the next poll or read will fail and exit the vnc_func
shutdown(vnc_sock, 2);
vnc_sock_valid = false;
while((vnc_sock != -1) && (k < 60))
{
LOG("Waiting for vnc thread\n"); k++;
sleep(1);
}
}
LOG("Shutdown listener\n");
// you can't stop an accept once it has started.
// So set a flag and prod the listening thread into activity
listener_must_die = true;
self.sin_family = AF_INET;
if (get_numeric_res("vnc_port") == -1)
self.sin_port = 0;
else
self.sin_port = get_numeric_res("vnc_port");
self.sin_addr.s_addr = 0x7f000001; // local loop back
LOG("Trying to connect to self \n");
LOG("Result %d\n", connect(self_socket, &self, addrlen));
close(self_socket);
free( vnc_module.modes );
}
static int vopen(video_desc_t *org_vm )
{
LOG( "vopen called\n" );
vmode = *org_vm;
//LOG( "offs=%d rowbytes=%d width=%d heigh=%d depth=%d\n",
vmode.offs, vmode.rowbytes, vmode.w, vmode.h, vmode.depth );
if (is_open)
{
LOG("Open called twice!\n");
return 1;
}
pthread_mutex_lock(&buffers_mutex);
offscreen_buf = map_zero( NULL, FBBUF_SIZE(org_vm));
//LOG( "mapped offscreen_buf = %lx size = %d\n", (long)
offscreen_buf, FBBUF_SIZE(org_vm) );
//output_buf_size = org_vm->w * 4;
output_buf_size = 10000;
output_buf = malloc( output_buf_size );
//LOG( "output_buf = %lx size = %ld\n", (long) output_buf,
output_buf_size );
// Fill in the fields video.c expects
org_vm->mmu_flags = MAPPING_FB_ACCEL | MAPPING_FORCE_CACHE;
org_vm->map_base = 0;
org_vm->lvbase = offscreen_buf;
vmode = *org_vm;
offscreen_bpp = (vmode.depth + 7) / 8;
if (offscreen_bpp == 3) offscreen_bpp = 4;
_setup_fb_accel( vmode.lvbase+vmode.offs, vmode.rowbytes, vmode.h );
is_open = true;
pthread_mutex_unlock(&buffers_mutex);
return 0;
}
static void vclose( void )
{
//LOG( "vclose called\n" );
if( !is_open )
return;
is_open = false;
pthread_mutex_lock(&buffers_mutex);
_setup_fb_accel( NULL, 0, 0 );
munmap( offscreen_buf, FBBUF_SIZE(&vmode) );
offscreen_buf = NULL;
free(output_buf);
output_buf = NULL;
output_buf_size = 0;
pthread_mutex_unlock(&buffers_mutex);
}
static void vrefresh( void )
{
force_redraw = true;
}
static void setcmap(char *pal)
{
if (vmode.depth != 8)
return;
memcpy(mac_pal, pal, 256 * 3);
init_translationtable();
}
/* ***************************************************************
VNC functions
*************************************************************** */
void vnc_func(void *arg)
{
unsigned char buffer[256];
CARD32 encodingBuffer[20];
CARD32 auth = rfbNoAuth;
CARD8 lastbuttonmask = 0;
const rfbPixelFormat eight = { 8, 8, 1, 1, 3, 7, 7, 0, 2, 5 };
const rfbPixelFormat sixteen = { 16, 16, 1, 1, 31, 31, 31, 0, 5, 10 };
const rfbPixelFormat thirtytwo = { 32, 32, 1, 1, 255, 255, 255, 0, 8, 16 };
const char *display_name = "MOL via VNC";
int i;
rfbSetPixelFormatMsg set_pixels;
rfbSetEncodingsMsg set_encodings;
rfbFramebufferUpdateRequestMsg request;
rfbKeyEventMsg key;
rfbPointerEventMsg pointer;
rfbClientCutTextMsg cut;
rfbServerInitMsg server_init;
bool caps_on = false; // Flag: Caps Lock on
request_received = false;
LOG("vnc_func starts as pid %d\n", getpid());
snprintf(buffer, 256, rfbProtocolVersionFormat, rfbProtocolMajorVersion,
rfbProtocolMinorVersion);
if (!write_exact(buffer, 12)) goto endo;
if (!read_exact(buffer, 12)) goto endo;
if (!write_exact((unsigned char *)&auth, sizeof(auth))) goto endo;
if (!read_exact(buffer, sizeof(CARD8))) goto endo;
switch(vmode.depth)
{
case 8:
server_init.format = eight; break;
case 15:
case 16:
server_init.format = sixteen; break;
case 24:
case 32:
server_init.format = thirtytwo; break;
}
server_init.framebufferWidth = vmode.w;
server_init.framebufferHeight = vmode.h;
server_init.nameLength = strlen(display_name);
if (!write_exact((unsigned char *)&server_init, sizeof(server_init)))
goto endo;
if (!write_exact(display_name, strlen(display_name))) goto endo;
force_redraw = true;
while(vnc_sock_valid)
{
if (!read_exact(buffer, sizeof(CARD8)))
goto endo;
switch(buffer[0])
{
case rfbSetPixelFormat:
//LOG( "rfbSetPIxelFormat\n" );
if (!read_exact(((unsigned char *)&set_pixels) + 1,
sz_rfbSetPixelFormatMsg - 1) < 0) goto endo;
connection_running = true;
remote_format = set_pixels.format;
output_bpp = remote_format.bitsPerPixel / 8;
//LOG( "setting output_bpp to %d\n", output_bpp );
init_translationtable();
break;
case rfbSetEncodings:
if (!read_exact(((unsigned char *)&set_encodings) + 1,
sz_rfbSetEncodingsMsg - 1) < 0) goto endo;
//LOG( "rfbSetEncoding - %d encodings\n", set_encodings.nEncodings );
if (!read_exact((unsigned char*)&encodingBuffer,
sizeof(CARD32) * set_encodings.nEncodings) < 0)
goto endo;
g_CanHextile = false;
for(i=0;i < set_encodings.nEncodings; ++i)
{
//LOG( "rfbSetEncoding - likes %d\n", encodingBuffer[i] );
if ( encodingBuffer[i] == rfbEncodingHextile )
{
g_CanHextile = true;
break;
}
}
break;
case rfbFramebufferUpdateRequest:
//LOG( "update request\n" );
if (!read_exact(((unsigned char *)&request) + 1,
sz_rfbFramebufferUpdateRequestMsg - 1) < 0) goto endo;
request_received = true;
//send_update();
break;
case rfbKeyEvent:
{
int code;
//LOG( "rfbKeyEvent\n" );
if (!read_exact(((unsigned char *)&key) + 1,
sz_rfbKeyEventMsg - 1) < 0) goto endo;
code = ks_decode(key.key);
if (code == 0x39) // Caps Lock pressed
{
if ((!caps_on) && (key.down))
{
ADBKeyDown(code);
caps_on = true;
}
else if ((caps_on) && (!key.down))
{
ADBKeyUp(code);
caps_on = false;
}
break;
}
if (key.down)
{
ADBKeyDown(code);
}
else
{
ADBKeyUp(code);
}
break;
}
case rfbPointerEvent:
//LOG( "rfbPointerEvent\n" );
if (!read_exact(((unsigned char *)&pointer) + 1,
sz_rfbPointerEventMsg - 1) < 0) goto endo;
if (pointer.buttonMask != lastbuttonmask)
mouse_but_event( pointer.buttonMask ? kMouseEvent_Down1
: kMouseEvent_Up1);
lastbuttonmask = pointer.buttonMask;
mouse_move_to( pointer.x, pointer.y );
break;
case rfbClientCutText:
if (!read_exact(((unsigned char *)&cut) + 1,
sz_rfbClientCutTextMsg - 1) < 0) goto endo;
while(cut.length)
{
int i = cut.length;
if (i > 256) i = 255;
if (!read_exact(buffer, i) < 0) goto endo;
cut.length -= i;
}
break;
default:
LOG("Bad message %x\n", buffer[0]);
goto endo;
break;
}
}
endo:
connection_running = false;
LOG("Closing vnc_sock\n");
LOG("Result %d \n", close(vnc_sock));
vnc_sock_valid = false;
vnc_sock = -1;
LOG("------- vnc_func ends\n");
return;
}
void init_translationtable()
{
int i;
CARD16 tone = 0;
CARD32 ttwo;
CARD8 *pos;
if (!is_open) return;
if (!connection_running) return;
LOG("init_translationtable %d %d\n",
vmode.depth, remote_format.bitsPerPixel);
pos = (CARD8 *)translationtable;
switch(vmode.depth)
{
case 8:
for(i = 0; i < 256; i++)
{
switch(remote_format.bitsPerPixel)
{
case 8:
*(pos++) = IndexedToRemote(i);
break;
case 16:
tone = IndexedToRemote(i);
if (remote_format.bigEndian)
{
CARD16IntoCARD8Star(tone, pos);
}
else
{
SwapCARD16IntoCARD8Star(tone, pos);
}
break;
case 32:
ttwo = IndexedToRemote(i);
if (remote_format.bigEndian)
{
CARD32IntoCARD8Star(tone, pos);
}
else
{
SwapCARD32IntoCARD8Star(tone, pos);
}
break;
}
}
break;
case 16:
case 15:
for(i = 0; i < 65536; i++)
{
switch(remote_format.bitsPerPixel)
{
case 8:
translationtable[i] = RGB555ToRemote(i);
break;
case 16:
{
tone = RGB555ToRemote(i);
if (remote_format.bigEndian)
{
CARD16IntoCARD8Star(tone, pos);
}
else
{
SwapCARD16IntoCARD8Star(tone, pos);
}
break;
}
case 32:
{
ttwo = RGB555ToRemote(i);
if (remote_format.bigEndian)
{
CARD32IntoCARD8Star(ttwo, pos);
}
else
{
SwapCARD32IntoCARD8Star(ttwo, pos);
}
break;
}
}
}
break;
}
}
void send_update()
{
int i, y=-1, hight;
// struct timespec close_req = {0, 1}; /* 60 Hz */
rfbFramebufferUpdateMsg msg;
short dirty_buffer[80];
int dirty_size = 0;
// wait for sock and fb to become valid
if ((vnc_sock_valid == false) || (vnc_sock == -1) ||
(is_open == false) || (offscreen_buf == NULL))
{
//LOG( "sock/fb not ready, EXITING send_update\n" );
return;
}
if (force_redraw)
{
dirty_size = 1;
pthread_mutex_lock(&buffers_mutex);
_get_dirty_fb_lines(dirty_buffer, sizeof(dirty_buffer) );
pthread_mutex_unlock(&buffers_mutex);
dirty_buffer[0] = 0;
dirty_buffer[1] = vmode.h - 1;
force_redraw = false;
}
if (!dirty_size)
{
pthread_mutex_lock(&buffers_mutex);
dirty_size = _get_dirty_fb_lines(dirty_buffer, sizeof(dirty_buffer) );
pthread_mutex_unlock(&buffers_mutex);
}
if (!dirty_size)
{
return;
}
//LOG( "now sending update, size=%d\n", dirty_size );
msg.type = rfbFramebufferUpdate;
msg.nRects = dirty_size;
request_received = false;
// send the update
if (!write_exact((unsigned char *)&msg, sizeof(msg)))
{
//LOG( "failed to write update header\n" );
return;
}
for( i = 0; i < dirty_size; i++ )
{
y = dirty_buffer[i*2];
hight = dirty_buffer[i*2+1] - dirty_buffer[i*2] + 1;
if (!send_rect(0, y, vmode.w, hight))
{
//LOG( "failed to send rect, leaving send_update\n" );
return;
}
}
//LOG( "leaving send_update\n" );
}
static bool send_rect_hextile( int x, int y, int w, int h );
bool send_rect(int x, int y, int w, int h)
{
int hh;
bool res;
rfbFramebufferUpdateRectHeader rect;
//LOG("Send %dx%dx%dx%d Dep=(%d -> %d) Bpp=(%d -> %d)\n",
// x, y, w, h,
// vmode.depth, remote_format.bitsPerPixel,
// offscreen_bpp, output_bpp);
if ( g_CanHextile )
return send_rect_hextile( x, y, w, h );
//LOG( "sending rawdata\n" );
rect.encoding = 0;
rect.r.x = x;
rect.r.y = y;
rect.r.w = w;
rect.r.h = h;
//LOG("Send %d %d %d %d (%d -> %d) (%d -> %d)\n", x, y, w, h,
// vmode.depth, remote_format.bitsPerPixel,
// offscreen_bpp, output_bpp);
if(!write_exact((unsigned char *)&rect, sizeof(rect))) return false;
for(hh = 0; hh < h; hh ++)
{
pthread_mutex_lock(&buffers_mutex);
translate(offscreen_buf + vmode.offs + (x + (y + hh) * vmode.w)
* offscreen_bpp, output_buf, w);
res = write_exact(output_buf, w * output_bpp);
pthread_mutex_unlock(&buffers_mutex);
if(!res) return false;
}
return true;
}
void translate(unsigned char *in, unsigned char *out, int pixels)
{
int x;
CARD32 trans = 0;
CARD32 ttwo;
CARD32 *in32 = (CARD32 *)in;
CARD16 *in16 = (CARD16 *)in;
CARD8 *in8 = (CARD8 *)in;
//LOG( "translate( %lx, %lx, %d ) ( %d -> %d )\n", (long) in,
(long) out, pixels, vmode.depth, output_bpp );
if (vmode.depth != 32)
{
for(x = 0; x < pixels; x++)
{
switch(vmode.depth)
{
case 8:
trans = *(in8++);
break;
case 15:
case 16:
trans = *(in16++);
//LOG("input pixel is %04x\n", trans);
break;
default:
LOG("bad vmode.depth %d\n", vmode.depth);
return;
}
switch(output_bpp)
{
case 1:
out[x] = translationtable[trans];
break;
case 2:
*(out++) = translationtable[trans * 2];
*(out++) = translationtable[trans * 2 + 1];
break;
case 4:
*(out++) = translationtable[trans * 4];
*(out++) = translationtable[trans * 4 + 1];
*(out++) = translationtable[trans * 4 + 2];
*(out++) = translationtable[trans * 4 + 3];
break;
default:
LOG("bad output_bpp (1) %d\n", output_bpp);
return;
}
}
}
else
{
for(x = 0; x < pixels; x++)
{
trans = *(in32++);
ttwo = ARGB8888ToRemote(trans);
switch(output_bpp)
{
case 1:
out[x] = ttwo;
break;
case 2:
if (remote_format.bigEndian)
{
CARD16IntoCARD8Star(ttwo, out);
}
else
{
SwapCARD16IntoCARD8Star(ttwo, out);
}
break;
case 4:
if (remote_format.bigEndian)
{
CARD32IntoCARD8Star(ttwo, out);
}
else
{
SwapCARD32IntoCARD8Star(ttwo, out);
}
break;
default:
LOG("bad output_bpp (2) %d\n", output_bpp);
return;
}
}
}
}
bool send_rect_hextile( int x, int y, int w, int h )
{
//int hh;
//bool res;
rfbFramebufferUpdateRectHeader rect;
rect.encoding = rfbEncodingHextile;
//LOG( "send_rect_hextile( %d, %d, %d, %d )\n", x, y, w, h );
rect.r.x = x;
rect.r.y = y;
rect.r.w = w;
rect.r.h = h;
if ( !write_exact( (unsigned char*) &rect, sizeof(rect) ) )
{
LOG( "failed to write hextile header\n" );
return false;
}
switch( vmode.depth )
{
case 8:
return sendHextiles8( x, y, w, h );
break;
case 15:
case 16:
return sendHextiles16( x, y, w, h );
break;
case 32:
return sendHextiles32( x, y, w, h );
break;
default:
LOG("bad vmode.depth %d\n", vmode.depth);
return false;
}
return false;
}
static int ublen = 0;
static void copypixels( unsigned char* in,
unsigned char* out,
int ps,
int rw,
int w,
int h )
{
int y;
int rowBytes = w * ps;
int realRowBytes = rw * ps;
//LOG( "in=%lx out=%lx ps=%d rw=%d w=%d h=%d realRowBytes=%d
rowBytes=%d\n", (long) in, (long) out, ps, rw, w, h, realRowBytes,
rowBytes );
for( y = 0; y < h; ++y )
{
//LOG( "y=%d in=%lx out=%lx\n", y, (long) in, (long) out );
memcpy( out, in, rowBytes );
in += realRowBytes;
out += rowBytes;
}
}
#define PUT_PIXEL8(pix) (updateBuf[ublen++] = (pix))
#define PUT_PIXEL16(pix) (updateBuf[ublen++] = ((char*)&(pix))[0], \
updateBuf[ublen++] = ((char*)&(pix))[1])
#define PUT_PIXEL32(pix) (updateBuf[ublen++] = ((char*)&(pix))[0], \
updateBuf[ublen++] = ((char*)&(pix))[1], \
updateBuf[ublen++] = ((char*)&(pix))[2], \
updateBuf[ublen++] = ((char*)&(pix))[3])
#define DEFINE_SEND_HEXTILES(bpp) \
\
\
static bool subrectEncode##bpp(CARD##bpp *data, int w, int h, CARD##bpp bg, \
CARD##bpp fg, bool mono); \
static void testColours##bpp(CARD##bpp *data, int size, bool *mono, \
bool *solid, CARD##bpp *bg, CARD##bpp *fg); \
\
\
/* \
* rfbSendHextiles \
*/ \
\
static bool \
sendHextiles##bpp( int rx, int ry, int rw, int rh ) \
{ \
int x, y, w, h; \
int startUblen; \
CARD##bpp bg, fg, newBg, newFg; \
bool mono, solid; \
bool validBg = false; \
bool validFg = false; \
CARD##bpp clientPixelData[16*16*(bpp/8)]; \
int hh; \
unsigned char* updateBuf; \
unsigned char* fbptr; \
unsigned char* clptr; \
ublen = 0; \
bg = 0; \
fg = 0; \
newBg = 0; \
newFg = 0; \
updateBuf = output_buf; \
\
/* LOG( "sendHextiles%dbpp( %d, %d, %d, %d )\n", bpp, rx, ry, rw,
rh ); */ \
/* LOG( "offscreen_bpp=%d\n", offscreen_bpp ); */ \
\
for (y = ry; y < ry+rh; y += 16) { \
for (x = rx; x < rx+rw; x += 16) { \
\
w = h = 16; \
if (rx+rw - x < 16) \
w = rx+rw - x; \
if (ry+rh - y < 16) \
h = ry+rh - y; \
\
if ( (ublen + 1 + 16*16*(bpp/8)) > output_buf_size) { \
pthread_mutex_lock(&buffers_mutex); \
/* LOG( "Writing buffer %lx of length %d\n", (long)
output_buf, ublen ); */ \
if ( !write_exact(output_buf, ublen) ) \
{ \
pthread_mutex_unlock(&buffers_mutex); \
return false; \
} \
pthread_mutex_unlock(&buffers_mutex); \
\
ublen = 0; \
} \
\
\
/* LOG( "sending hextile(%dx%dx%dx%d) ofsb=%lx\n", x, y,
w, h, (long) offscreen_buf ); */ \
pthread_mutex_lock(&buffers_mutex); \
for( hh = 0; hh < h; ++hh ) \
{ \
/* LOG( "offscreen_buf=%lx hh=%d\n", (long)
offscreen_buf, hh ); */ \
fbptr = offscreen_buf + (x * offscreen_bpp) + (
(y+hh) * rw) * offscreen_bpp; \
clptr = ((unsigned char*) clientPixelData) + (hh*16)
* (bpp/8); \
\
/* copypixels( fbptr, (unsigned char*)
clientPixelData, bpp/8, rw, w, h ); */ \
translate( fbptr, clptr, w ); \
} \
pthread_mutex_unlock(&buffers_mutex); \
\
startUblen = ublen; \
updateBuf[startUblen] = 0; \
ublen++; \
\
testColours##bpp(clientPixelData, w * h, \
&mono, &solid, &newBg, &newFg); \
\
if (!validBg || (newBg != bg)) { \
validBg = true; \
bg = newBg; \
updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
PUT_PIXEL##bpp(bg); \
} \
\
if (solid) { \
continue; \
} \
\
updateBuf[startUblen] |= rfbHextileAnySubrects; \
\
if (mono) { \
if (!validFg || (newFg != fg)) { \
validFg = true; \
fg = newFg; \
updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
PUT_PIXEL##bpp(fg); \
} \
} else { \
validFg = false; \
updateBuf[startUblen] |= rfbHextileSubrectsColoured; \
} \
\
if (!subrectEncode##bpp(clientPixelData, w, h, bg, fg, mono)) { \
/* encoding was too large, use raw */ \
validBg = false; \
validFg = false; \
ublen = startUblen; \
updateBuf[ublen++] = rfbHextileRaw; \
\
/* LOG( "sending raw(%dx%dx%dx%d)\n", x, y, w, h ); */ \
pthread_mutex_lock(&buffers_mutex); \
for( hh = 0; hh < h; ++hh ) \
{ \
fbptr = offscreen_buf + (x * offscreen_bpp) +
( (y+hh) * rw) * offscreen_bpp; \
clptr = ((unsigned char*) clientPixelData) +
(hh*16) * (bpp/8); \
\
/* copypixels( fbptr, (unsigned char*)
clientPixelData, bpp/8, rw, w, h ); */ \
translate( fbptr, clptr, w ); \
} \
pthread_mutex_unlock(&buffers_mutex); \
memcpy( &updateBuf[ublen], (char*) clientPixelData, w
* h * (bpp/8) ); \
ublen += w * h * (bpp/8); \
} \
} \
} \
\
/* LOG( "Writing remaining buffer %lx of length %d\n", (long)
output_buf, ublen ); */ \
if ( ublen > 0 && !write_exact(output_buf, ublen) ) \
return false; \
ublen = 0; \
\
return true; \
} \
\
\
static bool \
subrectEncode##bpp(CARD##bpp *data, int w, int h, CARD##bpp bg, \
CARD##bpp fg, bool mono) \
{ \
CARD##bpp cl; \
int x,y; \
int i,j; \
int hx=0,hy,vx=0,vy; \
int hyflag; \
CARD##bpp *seg; \
CARD##bpp *line; \
int hw,hh,vw,vh; \
int thex,they,thew,theh; \
int numsubs = 0; \
int newLen; \
int nSubrectsUblen; \
unsigned char* updateBuf; \
updateBuf = output_buf; \
\
nSubrectsUblen = ublen; \
ublen++; \
\
for (y=0; y<h; y++) { \
line = data+(y*w); \
for (x=0; x<w; x++) { \
if (line[x] != bg) { \
cl = line[x]; \
hy = y-1; \
hyflag = 1; \
for (j=y; j<h; j++) { \
seg = data+(j*w); \
if (seg[x] != cl) {break;} \
i = x; \
while ((seg[i] == cl) && (i < w)) i += 1; \
i -= 1; \
if (j == y) vx = hx = i; \
if (i < vx) vx = i; \
if ((hyflag > 0) && (i >= hx)) { \
hy += 1; \
} else { \
hyflag = 0; \
} \
} \
vy = j-1; \
\
/* We now have two possible subrects: (x,y,hx,hy) and \
* (x,y,vx,vy). We'll choose the bigger of the two. \
*/ \
hw = hx-x+1; \
hh = hy-y+1; \
vw = vx-x+1; \
vh = vy-y+1; \
\
thex = x; \
they = y; \
\
if ((hw*hh) > (vw*vh)) { \
thew = hw; \
theh = hh; \
} else { \
thew = vw; \
theh = vh; \
} \
\
if (mono) { \
newLen = ublen - nSubrectsUblen + 2; \
} else { \
newLen = ublen - nSubrectsUblen + bpp/8 + 2; \
} \
\
if (newLen > (w * h * (bpp/8))) \
return false; \
\
numsubs += 1; \
\
if (!mono) PUT_PIXEL##bpp(cl); \
\
updateBuf[ublen++] = rfbHextilePackXY(thex,they); \
updateBuf[ublen++] = rfbHextilePackWH(thew,theh); \
\
/* \
* Now mark the subrect as done. \
*/ \
for (j=they; j < (they+theh); j++) { \
for (i=thex; i < (thex+thew); i++) { \
data[j*w+i] = bg; \
} \
} \
} \
} \
} \
\
updateBuf[nSubrectsUblen] = numsubs; \
\
return true; \
} \
\
\
/* \
* testColours() tests if there are one (solid), two (mono) or more \
* colours in a tile and gets a reasonable guess at the best background \
* pixel, and the foreground pixel for mono. \
*/ \
\
static void \
testColours##bpp(data,size,mono,solid,bg,fg) \
CARD##bpp *data; \
int size; \
bool *mono; \
bool *solid; \
CARD##bpp *bg; \
CARD##bpp *fg; \
{ \
CARD##bpp colour1, colour2; \
int n1 = 0, n2 = 0; \
*mono = true; \
*solid = true; \
colour1 = 0; \
colour2 = 0; \
\
for (; size > 0; size--, data++) { \
\
if (n1 == 0) \
colour1 = *data; \
\
if (*data == colour1) { \
n1++; \
continue; \
} \
\
if (n2 == 0) { \
*solid = false; \
colour2 = *data; \
} \
\
if (*data == colour2) { \
n2++; \
continue; \
} \
\
*mono = false; \
break; \
} \
\
if (n1 > n2) { \
*bg = colour1; \
*fg = colour2; \
} else { \
*bg = colour2; \
*fg = colour1; \
} \
}
DEFINE_SEND_HEXTILES(8)
DEFINE_SEND_HEXTILES(16)
DEFINE_SEND_HEXTILES(32)
// functions called from fb_watch_thread and vnc_thread
bool read_exact(unsigned char *buffer, int size)
{
int p = 0;
int i = 0;
if (!vnc_sock_valid) return false;
while (p < size)
{
struct pollfd polls;
int retval = 1;
if (request_received)
{
polls.fd = vnc_sock;
polls.events = POLLIN;
retval = poll(&polls, 1, 1000 / 10);
}
if (retval > 0)
{
i = read( vnc_sock, buffer + p, size - p);
if (i <= 0)
{
LOG("Error on socket read %d\n", i);
perror("Read from socket");
vnc_sock_valid = false;
return false;
}
p += i;
}
if (request_received)
{
send_update();
}
}
return true;
}
bool write_exact(const unsigned char *buffer, int size)
{
int p = 0;
int i = 0;
if (!vnc_sock_valid) return false;
while (p < size)
{
i = write( vnc_sock, buffer + p, size - p);
if (i < 0)
{
LOG("Error on socket write\n");
perror("Write to socket");
// assume the socket is broken
vnc_sock_valid = false;
return false;
}
p += i;
}
return true;
}
static int ks_decode(CARD32 ks)
{
/* keysym to mac keycode translation */
switch (ks) {
case XK_A: case XK_a: return 0x00;
case XK_B: case XK_b: return 0x0b;
case XK_C: case XK_c: return 0x08;
case XK_D: case XK_d: return 0x02;
case XK_E: case XK_e: return 0x0e;
case XK_F: case XK_f: return 0x03;
case XK_G: case XK_g: return 0x05;
case XK_H: case XK_h: return 0x04;
case XK_I: case XK_i: return 0x22;
case XK_J: case XK_j: return 0x26;
case XK_K: case XK_k: return 0x28;
case XK_L: case XK_l: return 0x25;
case XK_M: case XK_m: return 0x2e;
case XK_N: case XK_n: return 0x2d;
case XK_O: case XK_o: return 0x1f;
case XK_P: case XK_p: return 0x23;
case XK_Q: case XK_q: return 0x0c;
case XK_R: case XK_r: return 0x0f;
case XK_S: case XK_s: return 0x01;
case XK_T: case XK_t: return 0x11;
case XK_U: case XK_u: return 0x20;
case XK_V: case XK_v: return 0x09;
case XK_W: case XK_w: return 0x0d;
case XK_X: case XK_x: return 0x07;
case XK_Y: case XK_y: return 0x10;
case XK_Z: case XK_z: return 0x06;
case XK_1: case XK_exclam: return 0x12;
case XK_2: case XK_at: return 0x13;
case XK_3: case XK_numbersign: return 0x14;
case XK_4: case XK_dollar: return 0x15;
case XK_5: case XK_percent: return 0x17;
case XK_6: return 0x16;
case XK_7: case XK_ampersand: return 0x1a;
case XK_8: case XK_asterisk: return 0x1c;
case XK_9: case XK_parenleft: return 0x19;
case XK_0: case XK_parenright: return 0x1d;
case XK_grave: case XK_asciitilde: return 0x0a;
case XK_minus: case XK_underscore: return 0x1b;
case XK_equal: case XK_plus: return 0x18;
case XK_bracketleft:
case XK_braceleft: return 0x21;
case XK_bracketright:
case XK_braceright: return 0x1e;
case XK_backslash: case XK_bar: return 0x2a;
case XK_semicolon: case XK_colon: return 0x29;
case XK_apostrophe: case XK_quotedbl: return 0x27;
case XK_comma: case XK_less: return 0x2b;
case XK_period: case XK_greater: return 0x2f;
case XK_slash: case XK_question: return 0x2c;
case XK_Tab: return 0x30;
case XK_Return: return 0x24;
case XK_space: return 0x31;
case XK_BackSpace: return 0x33;
case XK_Delete: return 0x75;
case XK_Insert: return 0x72;
case XK_Home: case XK_Help: return 0x73;
case XK_End: return 0x77;
#ifdef __hpux
case XK_Prior: return 0x74;
case XK_Next: return 0x79;
#else
case XK_Page_Up: return 0x74;
case XK_Page_Down: return 0x79;
#endif
case XK_Control_L: return 0x36;
case XK_Control_R: return 0x36;
case XK_Shift_L: return 0x38;
case XK_Shift_R: return 0x38;
case XK_Mode_switch: return 0x37; /* Mac Command */
case XK_Meta_L: return 0x37;
case XK_Meta_R: return 0x37;
case XK_Alt_L: return 0x3a; /* Mac Alt */
case XK_Alt_R: return 0x3a;
case XK_Menu: return 0x32;
case XK_Caps_Lock: return 0x39;
case XK_Num_Lock: return 0x47;
case XK_Up: return 0x3e;
case XK_Down: return 0x3d;
case XK_Left: return 0x3b;
case XK_Right: return 0x3c;
case XK_Escape: return 0x35;
case XK_F1: return 0x7a;
case XK_F2: return 0x78;
case XK_F3: return 0x63;
case XK_F4: return 0x76;
case XK_F5: return 0x60;
case XK_F6: return 0x61;
case XK_F7: return 0x62;
case XK_F8: return 0x64;
case XK_F9: return 0x65;
case XK_F10: return 0x6d;
case XK_F11: return 0x67;
case XK_F12: return 0x6f;
case XK_Print: return 0x69;
case XK_Scroll_Lock: return 0x6b;
case XK_Pause: return 0x71;
#if defined(XK_KP_Prior) && defined(XK_KP_Left) &&
defined(XK_KP_Insert) && defined (XK_KP_End)
case XK_KP_0: case XK_KP_Insert: return 0x52;
case XK_KP_1: case XK_KP_End: return 0x53;
case XK_KP_2: case XK_KP_Down: return 0x54;
case XK_KP_3: case XK_KP_Next: return 0x55;
case XK_KP_4: case XK_KP_Left: return 0x56;
case XK_KP_5: case XK_KP_Begin: return 0x57;
case XK_KP_6: case XK_KP_Right: return 0x58;
case XK_KP_7: case XK_KP_Home: return 0x59;
case XK_KP_8: case XK_KP_Up: return 0x5b;
case XK_KP_9: case XK_KP_Prior: return 0x5c;
case XK_KP_Decimal: case XK_KP_Delete: return 0x41;
#else
case XK_KP_0: return 0x52;
case XK_KP_1: return 0x53;
case XK_KP_2: return 0x54;
case XK_KP_3: return 0x55;
case XK_KP_4: return 0x56;
case XK_KP_5: return 0x57;
case XK_KP_6: return 0x58;
case XK_KP_7: return 0x59;
case XK_KP_8: return 0x5b;
case XK_KP_9: return 0x5c;
case XK_KP_Decimal: return 0x41;
#endif
case XK_KP_Add: return 0x45;
case XK_KP_Subtract: return 0x4e;
case XK_KP_Multiply: return 0x43;
case XK_KP_Divide: return 0x4b;
case XK_KP_Enter: return 0x4c;
case XK_KP_Equal: return 0x51;
}
return ~0;
}
/* ***************************************************************
The listener
*************************************************************** */
void listen_func(void *arg)
{
// init
int one = 1;
struct sockaddr_in addr;
int new_socket = 0;
int addrlen = sizeof(addr);
int listen_sock = 0;
LOG("VNC listen thread starts as pid %d\n", getpid());
listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sock < 0)
{
LOG("Cannot create Listening socket\n");
return;
}
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
(char*)&one, sizeof(one)) < 0)
{
LOG("Cannot setsockopt on Listening socket\n");
close(listen_sock);
return;
}
addr.sin_family = AF_INET;
if (get_numeric_res("vnc_port") == -1)
addr.sin_port = 0;
else
addr.sin_port = get_numeric_res("vnc_port");
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
LOG("Cannot bind on Listening socket\n");
close(listen_sock);
return;
}
LOG( "Started listen. Serving VNC on port %d\n", addr.sin_port);
if (listen(listen_sock, 5) < 0)
{
LOG("Cannot listen on Listening socket\n");
close(listen_sock);
return;
}
while((new_socket = accept(listen_sock,
(struct sockaddr *)&addr, &addrlen)) >= 0)
{
if (listener_must_die)
break;
LOG("Accepted incoming\n");
if (vnc_sock != -1)
{
// there is already a vnc thread running
LOG("Vnc connection rejected. Connection is already in progress (%d)\n",
vnc_sock);
close(new_socket);
}
else
{
vnc_sock = new_socket;
vnc_sock_valid = true;
if (!create_thread( vnc_func, NULL, "VNC-thread"))
{
LOG("Cannot start thread\n");
close(new_socket);
}
}
}
// close
LOG("Close Listening socket\n");
close(listen_sock);
listen_sock = -1;
return;
}
This archive was generated by hypermail 2a24 : Sun Sep 24 2000 - 15:51:33 MDT