Home | History | Annotate | Download | only in vncterm
      1 #include <stdarg.h>
      2 #include <rfb/keysym.h>
      3 #include "VNConsole.h"
      4 
      5 #define DEBUG(x)
      6 
      7 unsigned char colourMap16[16*3]={
      8   /* 0 black       #000000 */ 0x00,0x00,0x00,
      9   /* 1 maroon      #800000 */ 0x80,0x00,0x00,
     10   /* 2 green       #008000 */ 0x00,0x80,0x00,
     11   /* 3 khaki       #808000 */ 0x80,0x80,0x00,
     12   /* 4 navy        #000080 */ 0x00,0x00,0x80,
     13   /* 5 purple      #800080 */ 0x80,0x00,0x80,
     14   /* 6 aqua-green  #008080 */ 0x00,0x80,0x80,
     15   /* 7 light grey  #c0c0c0 */ 0xc0,0xc0,0xc0,
     16   /* 8 dark grey   #808080 */ 0x80,0x80,0x80,
     17   /* 9 red         #ff0000 */ 0xff,0x00,0x00,
     18   /* a light green #00ff00 */ 0x00,0xff,0x00,
     19   /* b yellow      #ffff00 */ 0xff,0xff,0x00,
     20   /* c blue        #0000ff */ 0x00,0x00,0xff,
     21   /* d pink        #ff00ff */ 0xff,0x00,0xff,
     22   /* e light blue  #00ffff */ 0x00,0xff,0xff,
     23   /* f white       #ffffff */ 0xff,0xff,0xff
     24 };
     25 
     26 void MakeColourMap16(vncConsolePtr c)
     27 {
     28   rfbColourMap* colourMap=&(c->screen->colourMap);
     29   if(colourMap->count)
     30     free(colourMap->data.bytes);
     31   colourMap->data.bytes=malloc(16*3);
     32   memcpy(colourMap->data.bytes,colourMap16,16*3);
     33   colourMap->count=16;
     34   colourMap->is16=FALSE;
     35   c->screen->serverFormat.trueColour=FALSE;
     36 }
     37 
     38 void vcDrawOrHideCursor(vncConsolePtr c)
     39 {
     40   int i,j,w=c->screen->paddedWidthInBytes;
     41   char *b=c->screen->frameBuffer+c->y*c->cHeight*w+c->x*c->cWidth;
     42   for(j=c->cy1;j<c->cy2;j++)
     43     for(i=c->cx1;i<c->cx2;i++)
     44       b[j*w+i]^=0x0f;
     45   rfbMarkRectAsModified(c->screen,
     46 			c->x*c->cWidth+c->cx1,c->y*c->cHeight+c->cy1,
     47 			c->x*c->cWidth+c->cx2,c->y*c->cHeight+c->cy2);
     48   c->cursorIsDrawn=c->cursorIsDrawn?FALSE:TRUE;
     49 }
     50 
     51 void vcDrawCursor(vncConsolePtr c)
     52 {
     53   if(c->cursorActive && c->y<c->height && c->x<c->width) {
     54     /* rfbLog("DrawCursor: %d,%d\n",c->x,c->y); */
     55     vcDrawOrHideCursor(c);
     56   }
     57 }
     58 
     59 void vcHideCursor(vncConsolePtr c)
     60 {
     61   if(c->currentlyMarking)
     62     vcUnmark(c);
     63   vcDrawOrHideCursor(c);
     64 }
     65 
     66 void vcMakeSureCursorIsDrawn(rfbClientPtr cl)
     67 {
     68   vncConsolePtr c=(vncConsolePtr)cl->screen->screenData;
     69   if(!c->dontDrawCursor)
     70     vcDrawCursor(c);
     71 }
     72 
     73 vncConsolePtr vcGetConsole(int *argc,char **argv,
     74 			   int width,int height,rfbFontDataPtr font
     75 #ifdef USE_ATTRIBUTE_BUFFER
     76 			   ,rfbBool withAttributes
     77 #endif
     78 			   )
     79 {
     80   vncConsolePtr c=(vncConsolePtr)malloc(sizeof(vncConsole));
     81 
     82   c->font=font;
     83   c->width=width;
     84   c->height=height;
     85   c->screenBuffer=(char*)malloc(width*height);
     86   memset(c->screenBuffer,' ',width*height);
     87 #ifdef USE_ATTRIBUTE_BUFFER
     88   if(withAttributes) {
     89     c->attributeBuffer=(char*)malloc(width*height);
     90     memset(c->attributeBuffer,0x07,width*height);
     91   } else
     92     c->attributeBuffer=NULL;
     93 #endif
     94   c->x=0;
     95   c->y=0;
     96   c->wrapBottomToTop=FALSE;
     97   c->cursorActive=TRUE;
     98   c->cursorIsDrawn=FALSE;
     99   c->dontDrawCursor=FALSE;
    100   c->inputBuffer=(char*)malloc(1024);
    101   c->inputSize=1024;
    102   c->inputCount=0;
    103   c->selection=0;
    104   c->selectTimeOut=40000; /* 40 ms */
    105   c->doEcho=TRUE;
    106 
    107   c->wasRightButtonDown=FALSE;
    108   c->currentlyMarking=FALSE;
    109 
    110   rfbWholeFontBBox(font,&c->xhot,&c->cHeight,&c->cWidth,&c->yhot);
    111   c->cWidth-=c->xhot;
    112   c->cHeight=-c->cHeight-c->yhot;
    113 
    114   /* text cursor */
    115   c->cx1=c->cWidth/8;
    116   c->cx2=c->cWidth*7/8;
    117   c->cy2=c->cHeight-1-c->yhot+c->cHeight/16;
    118   if(c->cy2>=c->cHeight)
    119     c->cy2=c->cHeight-1;
    120   c->cy1=c->cy2-c->cHeight/8;
    121   if(c->cy1<0)
    122     c->cy2=0;
    123 
    124   if(!(c->screen = rfbGetScreen(argc,argv,c->cWidth*c->width,c->cHeight*c->height,8,1,1)))
    125     return NULL;
    126   c->screen->screenData=(void*)c;
    127   c->screen->displayHook=vcMakeSureCursorIsDrawn;
    128   c->screen->frameBuffer=
    129     (char*)malloc(c->screen->width*c->screen->height);
    130   memset(c->screen->frameBuffer,c->backColour,
    131 	 c->screen->width*c->screen->height);
    132   c->screen->kbdAddEvent=vcKbdAddEventProc;
    133   c->screen->ptrAddEvent=vcPtrAddEventProc;
    134   c->screen->setXCutText=vcSetXCutTextProc;
    135 
    136   MakeColourMap16(c);
    137   c->foreColour=0x7;
    138   c->backColour=0;
    139 
    140   rfbInitServer(c->screen);
    141 
    142   return(c);
    143 }
    144 
    145 #include <rfb/rfbregion.h>
    146 
    147 /* before using this function, hide the cursor */
    148 void vcScroll(vncConsolePtr c,int lineCount)
    149 {
    150   int y1,y2;
    151   rfbScreenInfoPtr s=c->screen;
    152 
    153   if(lineCount==0)
    154     return;
    155 
    156   /* rfbLog("begin scroll\n"); */
    157   vcHideCursor(c);
    158   c->dontDrawCursor=TRUE;
    159 
    160   if(lineCount>=c->height || lineCount<=-c->height) {
    161     y1=0; y2=s->height;
    162   } else if(lineCount>0) {
    163     y1=s->height-lineCount*c->cHeight; y2=s->height;
    164     rfbDoCopyRect(s,0,0,s->width,y1,0,-lineCount*c->cHeight);
    165     memmove(c->screenBuffer,
    166 	    c->screenBuffer+(c->height-lineCount)*c->width,
    167 	    (c->height-lineCount)*c->width);
    168 #ifdef USE_ATTRIBUTE_BUFFER
    169     if(c->attributeBuffer)
    170 	    memmove(c->attributeBuffer,
    171 		    c->attributeBuffer+(c->height-lineCount)*c->width,
    172 		    (c->height-lineCount)*c->width);
    173 #endif
    174   } else {
    175     y1=0; y2=-lineCount*c->cHeight;
    176     rfbDoCopyRect(s,0,y2,s->width,s->height,0,-lineCount*c->cHeight);
    177     memmove(c->screenBuffer-lineCount*c->width,
    178 	    c->screenBuffer,
    179 	    (c->height+lineCount)*c->width);
    180 #ifdef USE_ATTRIBUTE_BUFFER
    181     if(c->attributeBuffer)
    182 	    memmove(c->attributeBuffer-lineCount*c->width,
    183 		    c->attributeBuffer,
    184 		    (c->height+lineCount)*c->width);
    185 #endif
    186   }
    187 
    188   c->dontDrawCursor=FALSE;
    189   memset(s->frameBuffer+y1*s->width,c->backColour,(y2-y1)*s->width);
    190   rfbMarkRectAsModified(s,0,y1-c->cHeight,s->width,y2);
    191   memset(c->screenBuffer+y1/c->cHeight*c->width,' ',
    192 	 (y2-y1)/c->cHeight*c->width);
    193 #ifdef USE_ATTRIBUTE_BUFFER
    194   if(c->attributeBuffer)
    195 	  memset(c->attributeBuffer+y1/c->cHeight*c->width,0x07,
    196 		 (y2-y1)/c->cHeight*c->width);
    197 #endif
    198   /* rfbLog("end scroll\n"); */
    199 }
    200 
    201 void vcCheckCoordinates(vncConsolePtr c)
    202 {
    203   if(c->x>=c->width) {
    204     c->x=0;
    205     c->y++;
    206   }
    207   if(c->y>=c->height) {
    208     if(c->wrapBottomToTop)
    209       c->y=0;
    210     else {
    211       vcScroll(c,c->y+1-c->height);
    212       c->y=c->height-1;
    213     }
    214   }
    215 }
    216 
    217 void vcPutChar(vncConsolePtr c,unsigned char ch)
    218 {
    219 #ifdef USE_ATTRIBUTE_BUFFER
    220   if(c->attributeBuffer) {
    221     unsigned char colour=c->attributeBuffer[c->x+c->y*c->width];
    222     vcPutCharColour(c,ch,colour&0x7,colour>>4);
    223   } else
    224 #endif
    225     vcPutCharColour(c,ch,c->foreColour,c->backColour);
    226 }
    227 
    228 void vcPutCharColour(vncConsolePtr c,unsigned char ch,unsigned char foreColour,unsigned char backColour)
    229 {
    230   rfbScreenInfoPtr s=c->screen;
    231   int j,x,y;
    232 
    233   vcHideCursor(c);
    234   if(ch<' ') {
    235     switch(ch) {
    236     case 7:
    237     case 13:
    238       break;
    239     case 8: /* BackSpace */
    240       if(c->x>0) {
    241 	c->x--;
    242 	vcPutChar(c,' ');
    243 	c->x--;
    244       }
    245       break;
    246     case 10: /* return */
    247       c->x=0;
    248       c->y++;
    249       vcCheckCoordinates(c);
    250       break;
    251     case 9: /* tabulator */
    252       do {
    253 	vcPutChar(c,' ');
    254       } while(c->x%8);
    255       break;
    256     default:
    257        rfbLog("putchar of unknown character: %c(%d).\n",ch,ch);
    258       vcPutChar(c,' ');
    259     }
    260   } else {
    261 #ifdef USE_ATTRIBUTE_BUFFER
    262     if(c->attributeBuffer)
    263       c->attributeBuffer[c->x+c->y*c->width]=foreColour|(backColour<<4);
    264 #endif
    265     x=c->x*c->cWidth;
    266     y=c->y*c->cHeight;
    267     for(j=y+c->cHeight-1;j>=y;j--)
    268       memset(s->frameBuffer+j*s->width+x,backColour,c->cWidth);
    269     rfbDrawChar(s,c->font,
    270 		x-c->xhot+(c->cWidth-rfbWidthOfChar(c->font,ch))/2,
    271 		y+c->cHeight-c->yhot-1,
    272 		ch,foreColour);
    273     c->screenBuffer[c->y*c->width+c->x]=ch;
    274     c->x++;
    275     rfbMarkRectAsModified(s,x,y-c->cHeight+1,x+c->cWidth,y+c->cHeight+1);
    276     vcCheckCoordinates(c);
    277   }
    278 }
    279 
    280 void vcPrint(vncConsolePtr c,unsigned char* str)
    281 {
    282   while(*str) {
    283     vcPutChar(c,*str);
    284     str++;
    285   }
    286 }
    287 
    288 void vcPrintColour(vncConsolePtr c,unsigned char* str,unsigned char foreColour,unsigned char backColour)
    289 {
    290   while(*str) {
    291     vcPutCharColour(c,*str,foreColour,backColour);
    292     str++;
    293   }
    294 }
    295 
    296 void vcPrintF(vncConsolePtr c,char* format,...)
    297 {
    298   va_list args;
    299   char buf[4096];
    300   va_start(args, format);
    301   vsprintf(buf, format, args);
    302   vcPrint(c,(unsigned char*)buf);
    303   va_end(args);
    304 }
    305 
    306 void vcPrintFColour(vncConsolePtr c,unsigned char foreColour,unsigned char backColour,char* format,...)
    307 {
    308   va_list args;
    309   char buf[4096];
    310   va_start(args, format);
    311   vsprintf(buf, format, args);
    312   vcPrintColour(c,(unsigned char*)buf,foreColour,backColour);
    313   va_end(args);
    314 }
    315 
    316 char vcGetCh(vncConsolePtr c)
    317 {
    318   if(c->inputCount>0) {
    319     char ch;
    320     ch=c->inputBuffer[0];
    321     c->inputCount--;
    322     if(c->inputCount>0)
    323       memmove(c->inputBuffer,c->inputBuffer+1,c->inputCount);
    324     return(ch);
    325   } else
    326     return(0);
    327 }
    328 
    329 char vcGetChar(vncConsolePtr c)
    330 {
    331   while(rfbIsActive(c->screen) && c->inputCount==0)
    332     vcProcessEvents(c);
    333   return(vcGetCh(c));
    334 }
    335 
    336 char *vcGetString(vncConsolePtr c,char *buffer,int bufferSize)
    337 {
    338   char *bufferBackup=c->inputBuffer;
    339   int i,count=bufferSize-1;
    340 
    341   if(count>c->inputCount)
    342     count=c->inputCount;
    343   for(i=1;i<count && bufferBackup[i-1]!='\n';i++);
    344   if(i<count || i==bufferSize-1) {
    345     memcpy(buffer,bufferBackup,i);
    346     buffer[i+1]=0;
    347     c->inputCount-=i;
    348     memmove(bufferBackup,bufferBackup+i+2,c->inputCount);
    349     return(buffer);
    350   }
    351   memcpy(buffer,bufferBackup,c->inputCount);
    352   count=c->inputSize;
    353   c->inputSize=bufferSize;
    354   c->inputBuffer=buffer;
    355   while(rfbIsActive(c->screen)
    356       && c->inputCount<bufferSize-1 && buffer[c->inputCount-1]!='\n')
    357     vcProcessEvents(c);
    358   buffer[c->inputCount]=0;
    359   c->inputBuffer=bufferBackup;
    360   c->inputSize=count;
    361   c->inputCount=0;
    362   return(buffer);
    363 }
    364 
    365 void vcKbdAddEventProc(rfbBool down,rfbKeySym keySym,rfbClientPtr cl)
    366 {
    367   vncConsolePtr c=(vncConsolePtr)cl->screen->screenData;
    368   if(down) {
    369     if(c->inputCount<c->inputSize) {
    370       if(keySym<0 || keySym>0xff) {
    371 	if(keySym==XK_Return) keySym='\n';
    372 	else if(keySym==XK_BackSpace) keySym=8;
    373         else if(keySym==XK_Tab) keySym=9;
    374 	else keySym=0;
    375       }
    376       if(keySym>0) {
    377 	if(keySym==8) {
    378 	  if(c->inputCount>0)
    379 	    c->inputCount--;
    380 	} else
    381 	  c->inputBuffer[c->inputCount++]=(char)keySym;
    382 	if(c->doEcho)
    383 	  vcPutChar(c,(unsigned char)keySym);
    384       }
    385     }
    386   }
    387 }
    388 
    389 void vcPtrAddEventProc(int buttonMask,int x,int y,rfbClientPtr cl)
    390 {
    391   vncConsolePtr c=(vncConsolePtr)cl->screen->screenData;
    392 
    393   if(c->wasRightButtonDown) {
    394     if((buttonMask&4)==0) {
    395       if(c->selection) {
    396 	char* s;
    397 	for(s=c->selection;*s;s++) {
    398 	  c->screen->kbdAddEvent(1,*s,cl);
    399 	  c->screen->kbdAddEvent(0,*s,cl);
    400 	}
    401       }
    402       c->wasRightButtonDown=0;
    403     }
    404   } else if(buttonMask&4)
    405     c->wasRightButtonDown=1;
    406 
    407   if(buttonMask&1) {
    408     int cx=x/c->cWidth,cy=y/c->cHeight,pos;
    409     if(cx<0) cx=0; else if(cx>=c->width) cx=c->width-1;
    410     if(cy<0) cy=0; else if(cy>=c->height) cy=c->height-1;
    411     pos=cy*c->width+cx;
    412 
    413     /* mark */
    414     if(!c->currentlyMarking) {
    415       c->currentlyMarking=TRUE;
    416       c->markStart=pos;
    417       c->markEnd=pos;
    418       vcToggleMarkCell(c,pos);
    419     } else {
    420       DEBUG(rfbLog("markStart: %d, markEnd: %d, pos: %d\n",
    421 	      c->markStart,c->markEnd,pos));
    422       if(c->markEnd!=pos) {
    423 	if(c->markEnd<pos) {
    424 	  cx=c->markEnd; cy=pos;
    425 	} else {
    426 	  cx=pos; cy=c->markEnd;
    427 	}
    428 	if(cx<c->markStart) {
    429 	  if(cy<c->markStart)
    430 	    cy--;
    431 	} else
    432 	  cx++;
    433 	while(cx<=cy) {
    434 	  vcToggleMarkCell(c,cx);
    435 	  cx++;
    436 	}
    437 	c->markEnd=pos;
    438       }
    439     }
    440   } else if(c->currentlyMarking) {
    441     int i,j;
    442     if(c->markStart<c->markEnd) {
    443       i=c->markStart; j=c->markEnd+1;
    444     } else {
    445       i=c->markEnd; j=c->markStart;
    446     }
    447     if(c->selection) free(c->selection);
    448     c->selection=(char*)malloc(j-i+1);
    449     memcpy(c->selection,c->screenBuffer+i,j-i);
    450     c->selection[j-i]=0;
    451     vcUnmark(c);
    452     rfbGotXCutText(c->screen,c->selection,j-i);
    453   }
    454   rfbDefaultPtrAddEvent(buttonMask,x,y,cl);
    455 }
    456 
    457 void vcSetXCutTextProc(char* str,int len, struct _rfbClientRec* cl)
    458 {
    459   vncConsolePtr c=(vncConsolePtr)cl->screen->screenData;
    460 
    461   if(c->selection) free(c->selection);
    462   c->selection=(char*)malloc(len+1);
    463   memcpy(c->selection,str,len);
    464   c->selection[len]=0;
    465 }
    466 
    467 void vcToggleMarkCell(vncConsolePtr c,int pos)
    468 {
    469   int x=(pos%c->width)*c->cWidth,
    470     y=(pos/c->width)*c->cHeight;
    471   int i,j;
    472   rfbScreenInfoPtr s=c->screen;
    473   char *b=s->frameBuffer+y*s->width+x;
    474   for(j=0;j<c->cHeight;j++)
    475     for(i=0;i<c->cWidth;i++)
    476       b[j*s->width+i]^=0x0f;
    477   rfbMarkRectAsModified(c->screen,x,y,x+c->cWidth,y+c->cHeight);
    478 }
    479 
    480 void vcUnmark(vncConsolePtr c)
    481 {
    482   int i,j;
    483   c->currentlyMarking=FALSE;
    484   if(c->markStart<c->markEnd) {
    485     i=c->markStart; j=c->markEnd+1;
    486   } else {
    487     i=c->markEnd; j=c->markStart;
    488   }
    489   for(;i<j;i++)
    490     vcToggleMarkCell(c,i);
    491 }
    492 
    493 void vcProcessEvents(vncConsolePtr c)
    494 {
    495   rfbProcessEvents(c->screen,c->selectTimeOut);
    496 }
    497 
    498