手机探索者开发实录—Broncho支持VNC
手机探索者开发实录—Broncho支持VNC
转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>
在前段时间写的一篇BLOG中,我介绍了DirectFB同时显示到X11和VNC的方法。那是一个有趣的实验,为此我兴奋了好一会儿,不过没有什么太大的实用价值,因为broncho平台使用的GTK/DirectFB作为GUI,显示通过fbdev(framebuffer)输出到LCD。我们要做的是让DirectFB同时显示到fbdev和VNC上,这个功能作为手机探索者的一部分,现在是实现的时候了。这并不难,由于一些小问题,我还是花了一整天时间才搞定。
一、 下载libVNCServer,然后编译和安装。要确保通过环境变量PATH能找到vncserver的配置脚本。
二、 为DirectFB创建fbvnc的system模块。
1. 把fbdev拷贝为fbvnc,把所有的文件名、变量名和函数名,从fbdev改名为fbvnc。
2. 修改fbvnc.c,包含下列头文件。
3. 修改fbvnc.c,声明下列函数和变量。
4. 修改fbvnc.c,在primaryInitLayer中调用vnc_set_video_mode。
5. 修改fbvnc.c,实现下列函数。
三、 修改directfbrc,让system=fbvnc。
一切OK了(颜色还有点问题),在broncho上的效果图:

转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>
在前段时间写的一篇BLOG中,我介绍了DirectFB同时显示到X11和VNC的方法。那是一个有趣的实验,为此我兴奋了好一会儿,不过没有什么太大的实用价值,因为broncho平台使用的GTK/DirectFB作为GUI,显示通过fbdev(framebuffer)输出到LCD。我们要做的是让DirectFB同时显示到fbdev和VNC上,这个功能作为手机探索者的一部分,现在是实现的时候了。这并不难,由于一些小问题,我还是花了一整天时间才搞定。
一、 下载libVNCServer,然后编译和安装。要确保通过环境变量PATH能找到vncserver的配置脚本。
二、 为DirectFB创建fbvnc的system模块。
1. 把fbdev拷贝为fbvnc,把所有的文件名、变量名和函数名,从fbdev改名为fbvnc。
2. 修改fbvnc.c,包含下列头文件。
- #include<direct/thread.h>
- #include<core/input.h>
- #include<rfb/rfb.h>
- #include<rfb/keysym.h
3. 修改fbvnc.c,声明下列函数和变量。
- staticrfbScreenInfoPtrrfb_screen=NULL;
- staticCoreInputDevice*vncPointerDevice=NULL;
- staticCoreInputDevice*vncKeyboardDevice=NULL;
- staticintg_vnc_client_nr=0;
-
- typedefstruct_ClientData
- {
- intoldButtonMask;
- intpressed;
- intoldx;
- intoldy;
- }ClientData;
-
- staticvoidvnc_client_gone(rfbClientPtrcl);
- staticenumrfbNewClientActionvnc_client_new(rfbClientPtrcl);
- staticboolvnc_translate_key(rfbKeySymkey,DFBInputEvent*evt);
- staticvoid*vnc_server_thread(DirectThread*thread,void*data);
- staticvoid*vnc_refresh_thread(DirectThread*thread,void*data);
- staticvoidvnc_process_key_event(rfbBooldown,rfbKeySymkey,struct_rfbClientRec*cl);
- staticvoidvnc_process_pointer_event(intbuttonMask,intx,inty,struct_rfbClientRec*cl);
- staticDFBResultvnc_update_screen(unsignedshort*src,intx,inty,intw,inth);
- staticDFBResultvnc_set_video_mode(DFBDisplayLayerConfig*config);
- staticDFBEnumerationResultvnc_attach_keyboard_device(CoreInputDevice*device,void*ctx);
- staticDFBEnumerationResultvnc_attach_pointer_device(CoreInputDevice*device,void*ctx);
4. 修改fbvnc.c,在primaryInitLayer中调用vnc_set_video_mode。
5. 修改fbvnc.c,实现下列函数。
- staticDFBEnumerationResult
- vnc_attach_keyboard_device(CoreInputDevice*device,
- void*ctx)
- {
- vncKeyboardDevice=device;
- returnDFENUM_OK;
- }
-
- staticDFBEnumerationResult
- vnc_attach_pointer_device(CoreInputDevice*device,
- void*ctx)
- {
- vncPointerDevice=device;
-
- returnDFENUM_OK;
- }
- staticvoidvnc_client_gone(rfbClientPtrcl)
- {
- g_vnc_client_nr--;
- free(cl->clientData);
-
- return;
- }
-
- staticenumrfbNewClientActionvnc_client_new(rfbClientPtrcl)
- {
- g_vnc_client_nr++;
- cl->clientData=(void*)calloc(sizeof(ClientData),1);
- cl->clientGoneHook=vnc_client_gone;
- returnRFB_CLIENT_ACCEPT;
- }
-
-
- staticvoid
- vnc_process_pointer_event(intbuttonMask,intx,inty,rfbClientPtrcl)
- {
-
- DFBInputEventevt={0};
- intbutton=0;
-
- if(vncPointerDevice==NULL){
- /*Attachtofirstinputdevice*/
- dfb_input_enumerate_devices(vnc_attach_pointer_device,NULL,
- DICAPS_BUTTONS|DICAPS_AXES);
- D_ASSERT(vncPointerDevice);
- }
-
- ClientData*cd=cl->clientData;
- if(buttonMask!=cd->oldButtonMask){
- intmask=buttonMask^cd->oldButtonMask;
- if(mask&(1<<0)){
- button=DIBI_LEFT;
- }elseif(mask&(1<<1)){
- button=DIBI_MIDDLE;
- }elseif(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);
-
- }
-
- /*
- *declarationofprivatedata
- */
- staticvoid
- vnc_process_key_event(rfbBooldown,rfbKeySymkey,rfbClientPtrcl)
- {
- DFBInputEventevt;
- if(vncKeyboardDevice==NULL){
- /*Attachtofirstinputdevice*/
- dfb_input_enumerate_devices(vnc_attach_keyboard_device,NULL,DICAPS_KEYS);
- D_ASSERT(vncKeyboardDevice);
- }
- if(down)
- evt.type=DIET_KEYPRESS;
- else
- evt.type=DIET_KEYRELEASE;
- if(vnc_translate_key(key,&evt)){
- dfb_input_dispatch(vncKeyboardDevice,&evt);
- }
-
- }
-
-
- staticbool
- vnc_translate_key(rfbKeySymkey,DFBInputEvent*evt)
- {
- /*Unicode*/
- if(key<=0xf000){
- evt->flags=DIEF_KEYSYMBOL;
- evt->key_symbol=key;
- returntrue;
- }
-
- /*Deadkeys*/
- /*todo*/
-
- /*Numerickeypad*/
- if(key>=XK_KP_0&&key<=XK_KP_9){
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_0+key-XK_KP_0;
- returntrue;
- }
-
- /*Functionkeys*/
- if(key>=XK_F1&&key<=XK_F11){
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_F1+key-XK_F1;
- returntrue;
- }
-
- switch(key){
- /*Numerickeypad*/
- caseXK_KP_Decimal:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_DECIMAL;
- break;
-
- caseXK_KP_Separator:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_SEPARATOR;
- break;
-
- caseXK_KP_Divide:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_DIV;
- break;
-
- caseXK_KP_Multiply:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_MULT;
- break;
-
- caseXK_KP_Subtract:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_MINUS;
- break;
-
- caseXK_KP_Add:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_PLUS;
- break;
-
- caseXK_KP_Enter:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_ENTER;
- break;
-
- caseXK_KP_Equal:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_KP_EQUAL;
- break;
-
-
- /*Arrows+Home/Endpad*/
- caseXK_Up:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_UP;
- break;
-
- caseXK_Down:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_DOWN;
- break;
-
- caseXK_Right:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_RIGHT;
- break;
-
- caseXK_Left:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_LEFT;
- break;
-
- caseXK_Insert:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_INSERT;
- break;
- caseXK_Delete:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_DELETE;
- break;
-
- caseXK_Home:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_HOME;
- break;
-
- caseXK_End:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_END;
- break;
-
- caseXK_Page_Up:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_PAGE_UP;
- break;
-
- caseXK_Page_Down:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_PAGE_DOWN;
- break;
-
-
- /*Keystatemodifierkeys*/
- caseXK_Num_Lock:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_NUM_LOCK;
- break;
-
- caseXK_Caps_Lock:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_CAPS_LOCK;
- break;
-
- caseXK_Scroll_Lock:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_SCROLL_LOCK;
- break;
-
- caseXK_Shift_R:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_SHIFT_R;
- break;
-
- caseXK_Shift_L:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_SHIFT_L;
- break;
-
- caseXK_Control_R:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_CONTROL_R;
- break;
-
- caseXK_Control_L:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_CONTROL_L;
- break;
-
- caseXK_Alt_R:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_ALT_R;
- break;
-
- caseXK_Alt_L:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_ALT_L;
- break;
-
- caseXK_Meta_R:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_META_R;
- break;
-
- caseXK_Meta_L:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_META_L;
- break;
-
- caseXK_Super_L:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_SUPER_L;
- break;
-
- caseXK_Super_R:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_SUPER_R;
- break;
-
- caseXK_Hyper_L:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_HYPER_L;
- break;
- caseXK_Hyper_R:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_HYPER_R;
- break;
-
- /*case??:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_ALTGR;
- break;*/
- caseXK_BackSpace:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_BACKSPACE;
- break;
-
- caseXK_Tab:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_HYPER_L;
- break;
-
- caseXK_Return:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_ENTER;
- break;
-
- caseXK_Escape:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_ESCAPE;
- break;
-
- caseXK_Pause:
- evt->flags=DIEF_KEYID;
- evt->key_id=DIKI_PAUSE;
- break;
-
- /*Miscellaneousfunctionkeys*/
- caseXK_Help:
- evt->flags=DIEF_KEYSYMBOL;
- evt->key_symbol=DIKS_HELP;
- break;
-
- caseXK_Print:
- evt->flags=DIEF_KEYSYMBOL;
- evt->key_symbol=DIKS_PRINT;
- break;
-
- caseXK_Break:
- evt->flags=DIEF_KEYSYMBOL;
- evt->key_symbol=DIKS_BREAK;
- break;
-
- default:
- returnfalse;
- }
-
- returntrue;
- }
-
- #defineRGB16_TO_RGB32(pixel)((((pixel)&0xF800)<<8)|/
- (((pixel)&0x07E0)<<5)|/
- (((pixel)&0x001F)<<3))
-
- staticDFBResult
- vnc_update_screen(unsignedshort*src,intx,inty,intw,inth)
- {
- inti=0;
- intj=0;
- D_ASSERT(rfb_screen!=NULL);
- D_ASSERT(rfb_screen->frameBuffer!=NULL);
-
- if(g_vnc_client_nr<=0
- ||src==NULL
- ||rfb_screen==NULL
- ||rfb_screen->frameBuffer==NULL)
- {
- returnDFB_FALSE;
- }
-
- intd_bpp=4;
- char*dst=rfb_screen->frameBuffer;
- char*src_line=src;
- char*src_row=src;
- char*dst_line=dst;
- char*dst_row=dst;
- structfb_fix_screeninfo*fix=&(dfb_fbvnc->shared->fix);
- structfb_var_screeninfo*var=&(dfb_fbvnc->shared->current_var);
- ints_bpp=(var->bits_per_pixel+7)/8;
-
- if(w>var->xres_virtual
- ||h>var->yres_virtual)
- {
- returnDFB_FALSE;
- }
-
- for(i=y;i<h;i++)
- {
- src_row=src_line;
- dst_row=dst_line;
- for(j=x;j<w;j++)
- {
- src_row+=s_bpp;
- dst_row+=d_bpp;
- *(int*)dst_row=RGB16_TO_RGB32(*(short*)src_row);
- }
-
- src_line+=fix->line_length;
- dst_line=dst_row;
- }
- rfbMarkRectAsModified(rfb_screen,x,y,x+w,y+h);
-
- returnDFB_OK;
- }
-
- DFBResult
- vnc_set_video_mode(DFBDisplayLayerConfig*config)
- {
- intargc=0;
- char**argv=NULL;
- structfb_var_screeninfo*var=&(dfb_fbvnc->shared->current_var);
- intheight=var->yres_virtual;
- intwidth=var->xres_virtual;
-
- D_DEBUG("DirectFB/VNC:layerconfigproperties/n");
-
- if(rfb_screen)returnDFB_OK;
-
- rfb_screen=rfbGetScreen(&argc,argv,width,height,8,3,4);
- if(rfb_screen==NULL)
- {
- D_ERROR("DirectFB/VNC:Couldn'tset%dx%dx%dvideomode/n",
- config->width,config->height,
- config->pixelformat);
-
- returnDFB_FAILURE;
- }
- rfb_screen->frameBuffer=malloc(width*height*rfb_screen->depth/8);
- rfb_screen->kbdAddEvent=vnc_process_key_event;
- rfb_screen->ptrAddEvent=vnc_process_pointer_event;
- rfb_screen->newClientHook=vnc_client_new;
- rfbInitServer(rfb_screen);
- direct_thread_create(DTT_OUTPUT,vnc_server_thread,rfb_screen,"VNCOutput");
- direct_thread_create(DTT_OUTPUT,vnc_refresh_thread,rfb_screen,"VNCRefresh");
- returnDFB_OK;
- }
-
- staticvoid*
- vnc_server_thread(DirectThread*thread,void*data)
- {
- rfbRunEventLoop(rfb_screen,-1,FALSE);
-
- returnNULL;
- }
-
- staticvoid*
- vnc_refresh_thread(DirectThread*thread,void*data)
- {
- while(1)
- {
- if(dfb_fbvnc!=NULL&&dfb_fbvnc->framebuffer_base!=NULL&&g_vnc_client_nr>0)
- {
- vnc_update_screen(dfb_fbvnc->framebuffer_base,0,0,
- rfb_screen->width,rfb_screen->height);
- }
- usleep(200000);
- }
-
- returnNULL;
- }
三、 修改directfbrc,让system=fbvnc。
一切OK了(颜色还有点问题),在broncho上的效果图: