DirectFB同时显示到X11和VNC上
转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>
DirectFB可以使用多种后端作为输入输出设备,典型的有VNC、X11、SDL和fbdev等等,这种设计可以说非常巧妙了。但美中不足的是它在任意时刻只能使用一种后端,更换成其它后端需要重新起动DirectFB应用程序。大多数情况下,这也没有问题,但我想broncho手机在正常使用的情况下,还能通过VNC访问,这样就可以在PC上操作broncho手机的所有功能,甚至到把手机屏幕显示到投影仪上。
对于让DirectFB同时支持多个后端的情况,从设计的角度来看,当然是首选Composite模式,用一种新的后端把其它几个后端组合起来,即不用修改DirectFB框架,又不用修改现有的后端,改一下配置文件就行了。麻烦的是DirectFB-1.1.1中带的VNC根本就不能用,单进程的情况,那些问题我都修改掉了,支持多进程的情况遇到些困难了。最后懒得管它了,先给X11加上VNC功能试一下再说。
先编译LibVNCServer-0.9.1。从sf下载软件包,按正常方式编译即可。
接下来修改X11后端。
1.修改Makefile.am,连接VNC的库。
libdirectfb_x11_la_LDFLAGS = /
$(X11_LIBS) $(VNC_LIBS) /
-avoid-version /
-module
2.初始化VNC
int argc = 0;
char** argv = NULL;
D_DEBUG( "DirectFB/VNC: layer config properties/n");
if(rfb_screen) /*!!! FIXME*/
return DFB_OK;
/* Set video mode */
rfb_screen = rfbGetScreen(&argc, argv, config->width, config->height, 8,3,4);
if(DFB_COLOR_BITS_PER_PIXEL(config->format) == DSPF_RGB16)
{
rfb_screen->serverFormat.redShift = 11;
rfb_screen->serverFormat.greenShift = 5;
rfb_screen->serverFormat.blueShift = 0;
rfb_screen->serverFormat.redMax = 31;
rfb_screen->serverFormat.greenMax = 63;
rfb_screen->serverFormat.blueMax = 31;
}
rfb_screen->frameBuffer = malloc(rfb_screen->width * rfb_screen->height * rfb_screen->depth / 8) ;
rfb_screen->kbdAddEvent = process_key_event;
rfb_screen->ptrAddEvent = process_pointer_event;
rfb_screen->newClientHook = newclient;
rfbInitServer(rfb_screen);
direct_thread_create( DTT_OUTPUT, vnc_server_thread, rfb_screen, "VNC Output" );
if ( !(config->surface_caps & (DSCAPS_DOUBLE | DSCAPS_TRIPLE)) )
direct_thread_create( DTT_OUTPUT, vnc_refresh_thread, rfb_screen, "VNC Refresh" );
return DFB_OK;
3.更新VNC显示
static DFBResult
vnc_update_screen(void* src, int x, int y, int w, int h )
{
int i, j, k;
void *dst;
int pitch;
DFBResult ret;
unsigned short* p = NULL;
unsigned int* q = NULL;
D_ASSERT( surface != NULL );
D_ASSERT( rfb_screen != NULL );
D_ASSERT( rfb_screen->frameBuffer != NULL );
dst = rfb_screen->frameBuffer;
if(g_vnc_client_nr > 0)
{
direct_memcpy( dst, src, w * h * rfb_screen->depth/8 );
rfbMarkRectAsModified ( rfb_screen, x, y, x+w, y+h );
printf("%s %d %d %d %d/n", __func__, x, y, w, h);
}
return DFB_OK;
}
4.处理VNC输入
static void
process_pointer_event(int buttonMask, int x, int y, rfbClientPtr cl)
{
DFBInputEvent evt = {0};
int button = 0;
if( vncPointerDevice == NULL ){
/* Attach to first input device */
dfb_input_enumerate_devices( attach_pointer_device,NULL,
DICAPS_BUTTONS|DICAPS_AXES);
D_ASSERT(vncPointerDevice);
}
ClientData* cd=cl->clientData;
if(buttonMask != cd->oldButtonMask ) {
int mask = buttonMask^cd->oldButtonMask;
if( mask & (1 << 0)) {
button=DIBI_LEFT;
} else if( mask & (1 << 1)) {
button=DIBI_MIDDLE;
} else if( mask & (1 << 2)) {
button=DIBI_RIGHT;
} else {
return;
}
evt.flags = DIEF_NONE;
if(cd->pressed)
{
evt.type = DIET_BUTTONRELEASE;
cd->pressed=0;
cd->oldButtonMask = 0;
}else {
evt.type = DIET_BUTTONPRESS;
cd->pressed=1;
cd->oldButtonMask=buttonMask;
}
evt.button=button;
printf("%s %d %d %d %d/n", __func__, button, cd->pressed, x, y);
dfb_input_dispatch( vncPointerDevice, &evt );
cd->oldx=x;
cd->oldy=y;
return;
}
evt.type = DIET_AXISMOTION;
evt.flags = DIEF_AXISABS;
if( cd->oldx != x ) {
evt.axis = DIAI_X;
evt.axisabs = x;
dfb_input_dispatch( vncPointerDevice, &evt );
}
if( cd->oldy != y ) {
evt.axis = DIAI_Y;
evt.axisabs = y;
dfb_input_dispatch( vncPointerDevice, &evt );
}
cd->oldx=x;
cd->oldy=y;
dfb_input_dispatch( vncPointerDevice, &evt );
rfbDefaultPtrAddEvent(buttonMask,x,y,cl);
}
static void
process_key_event(rfbBool down, rfbKeySym key, rfbClientPtr cl)
{
DFBInputEvent evt;
if( vncKeyboardDevice == NULL ){
/* Attach to first input device */
dfb_input_enumerate_devices( attach_keyboard_device,NULL, DICAPS_KEYS);
D_ASSERT(vncKeyboardDevice);
}
if (down)
evt.type = DIET_KEYPRESS;
else
evt.type = DIET_KEYRELEASE;
if (translate_key( key, &evt )) {
dfb_input_dispatch( vncKeyboardDevice, &evt );
}
}
5.处理VNC客户端连接
static void clientgone(rfbClientPtr cl)
{
g_vnc_client_nr--;
free(cl->clientData);
return;
}
static enum rfbNewClientAction newclient(rfbClientPtr cl)
{
g_vnc_client_nr++;
cl->clientData = (void*)calloc(sizeof(ClientData),1);
cl->clientGoneHook = clientgone;
return RFB_CLIENT_ACCEPT;
}
编译完成后运行broncho,然后用VNC viewer连接到本机,效果如下:
色彩有点不对,有时间再看看。
~~end~~
转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>
DirectFB可以使用多种后端作为输入输出设备,典型的有VNC、X11、SDL和fbdev等等,这种设计可以说非常巧妙了。但美中不足的是它在任意时刻只能使用一种后端,更换成其它后端需要重新起动DirectFB应用程序。大多数情况下,这也没有问题,但我想broncho手机在正常使用的情况下,还能通过VNC访问,这样就可以在PC上操作broncho手机的所有功能,甚至到把手机屏幕显示到投影仪上。
对于让DirectFB同时支持多个后端的情况,从设计的角度来看,当然是首选Composite模式,用一种新的后端把其它几个后端组合起来,即不用修改DirectFB框架,又不用修改现有的后端,改一下配置文件就行了。麻烦的是DirectFB-1.1.1中带的VNC根本就不能用,单进程的情况,那些问题我都修改掉了,支持多进程的情况遇到些困难了。最后懒得管它了,先给X11加上VNC功能试一下再说。
先编译LibVNCServer-0.9.1。从sf下载软件包,按正常方式编译即可。
接下来修改X11后端。
1.修改Makefile.am,连接VNC的库。
libdirectfb_x11_la_LDFLAGS = /
$(X11_LIBS) $(VNC_LIBS) /
-avoid-version /
-module
2.初始化VNC
int argc = 0;
char** argv = NULL;
D_DEBUG( "DirectFB/VNC: layer config properties/n");
if(rfb_screen) /*!!! FIXME*/
return DFB_OK;
/* Set video mode */
rfb_screen = rfbGetScreen(&argc, argv, config->width, config->height, 8,3,4);
if(DFB_COLOR_BITS_PER_PIXEL(config->format) == DSPF_RGB16)
{
rfb_screen->serverFormat.redShift = 11;
rfb_screen->serverFormat.greenShift = 5;
rfb_screen->serverFormat.blueShift = 0;
rfb_screen->serverFormat.redMax = 31;
rfb_screen->serverFormat.greenMax = 63;
rfb_screen->serverFormat.blueMax = 31;
}
rfb_screen->frameBuffer = malloc(rfb_screen->width * rfb_screen->height * rfb_screen->depth / 8) ;
rfb_screen->kbdAddEvent = process_key_event;
rfb_screen->ptrAddEvent = process_pointer_event;
rfb_screen->newClientHook = newclient;
rfbInitServer(rfb_screen);
direct_thread_create( DTT_OUTPUT, vnc_server_thread, rfb_screen, "VNC Output" );
if ( !(config->surface_caps & (DSCAPS_DOUBLE | DSCAPS_TRIPLE)) )
direct_thread_create( DTT_OUTPUT, vnc_refresh_thread, rfb_screen, "VNC Refresh" );
return DFB_OK;
3.更新VNC显示
static DFBResult
vnc_update_screen(void* src, int x, int y, int w, int h )
{
int i, j, k;
void *dst;
int pitch;
DFBResult ret;
unsigned short* p = NULL;
unsigned int* q = NULL;
D_ASSERT( surface != NULL );
D_ASSERT( rfb_screen != NULL );
D_ASSERT( rfb_screen->frameBuffer != NULL );
dst = rfb_screen->frameBuffer;
if(g_vnc_client_nr > 0)
{
direct_memcpy( dst, src, w * h * rfb_screen->depth/8 );
rfbMarkRectAsModified ( rfb_screen, x, y, x+w, y+h );
printf("%s %d %d %d %d/n", __func__, x, y, w, h);
}
return DFB_OK;
}
4.处理VNC输入
static void
process_pointer_event(int buttonMask, int x, int y, rfbClientPtr cl)
{
DFBInputEvent evt = {0};
int button = 0;
if( vncPointerDevice == NULL ){
/* Attach to first input device */
dfb_input_enumerate_devices( attach_pointer_device,NULL,
DICAPS_BUTTONS|DICAPS_AXES);
D_ASSERT(vncPointerDevice);
}
ClientData* cd=cl->clientData;
if(buttonMask != cd->oldButtonMask ) {
int mask = buttonMask^cd->oldButtonMask;
if( mask & (1 << 0)) {
button=DIBI_LEFT;
} else if( mask & (1 << 1)) {
button=DIBI_MIDDLE;
} else if( mask & (1 << 2)) {
button=DIBI_RIGHT;
} else {
return;
}
evt.flags = DIEF_NONE;
if(cd->pressed)
{
evt.type = DIET_BUTTONRELEASE;
cd->pressed=0;
cd->oldButtonMask = 0;
}else {
evt.type = DIET_BUTTONPRESS;
cd->pressed=1;
cd->oldButtonMask=buttonMask;
}
evt.button=button;
printf("%s %d %d %d %d/n", __func__, button, cd->pressed, x, y);
dfb_input_dispatch( vncPointerDevice, &evt );
cd->oldx=x;
cd->oldy=y;
return;
}
evt.type = DIET_AXISMOTION;
evt.flags = DIEF_AXISABS;
if( cd->oldx != x ) {
evt.axis = DIAI_X;
evt.axisabs = x;
dfb_input_dispatch( vncPointerDevice, &evt );
}
if( cd->oldy != y ) {
evt.axis = DIAI_Y;
evt.axisabs = y;
dfb_input_dispatch( vncPointerDevice, &evt );
}
cd->oldx=x;
cd->oldy=y;
dfb_input_dispatch( vncPointerDevice, &evt );
rfbDefaultPtrAddEvent(buttonMask,x,y,cl);
}
static void
process_key_event(rfbBool down, rfbKeySym key, rfbClientPtr cl)
{
DFBInputEvent evt;
if( vncKeyboardDevice == NULL ){
/* Attach to first input device */
dfb_input_enumerate_devices( attach_keyboard_device,NULL, DICAPS_KEYS);
D_ASSERT(vncKeyboardDevice);
}
if (down)
evt.type = DIET_KEYPRESS;
else
evt.type = DIET_KEYRELEASE;
if (translate_key( key, &evt )) {
dfb_input_dispatch( vncKeyboardDevice, &evt );
}
}
5.处理VNC客户端连接
static void clientgone(rfbClientPtr cl)
{
g_vnc_client_nr--;
free(cl->clientData);
return;
}
static enum rfbNewClientAction newclient(rfbClientPtr cl)
{
g_vnc_client_nr++;
cl->clientData = (void*)calloc(sizeof(ClientData),1);
cl->clientGoneHook = clientgone;
return RFB_CLIENT_ACCEPT;
}
编译完成后运行broncho,然后用VNC viewer连接到本机,效果如下:
色彩有点不对,有时间再看看。
~~end~~