2013-08-06 12:58:17 +04:00
/*
2013-09-11 14:08:08 +04:00
Copyright ( C ) 2013 Proxmox Server Solutions GmbH
2013-08-06 12:58:17 +04:00
2013-09-11 14:08:08 +04:00
Copyright : spiceterm is under GNU GPL , the GNU General Public License .
2013-08-06 12:58:17 +04:00
2013-09-11 14:08:08 +04:00
This program 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 ; version 2 dated June , 1991.
2013-08-06 12:58:17 +04:00
2013-09-11 14:08:08 +04:00
This program 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 .
2013-08-06 12:58:17 +04:00
2013-09-11 14:08:08 +04:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA
02111 - 1307 , USA .
2013-08-06 12:58:17 +04:00
2013-09-11 14:08:08 +04:00
Author : Dietmar Maurer < dietmar @ proxmox . com >
2013-09-12 09:16:03 +04:00
Note : most of the code here is copied from vncterm ( which is
2013-09-11 14:08:08 +04:00
also written by me ) .
2013-08-06 12:58:17 +04:00
*/
2013-09-12 09:16:03 +04:00
# define _GNU_SOURCE
2013-09-10 15:05:05 +04:00
2013-08-06 12:58:17 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
2013-08-21 09:43:55 +04:00
# include <sys/types.h>
2013-08-06 12:58:17 +04:00
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <pty.h> /* for openpty and forkpty */
# include <string.h>
# include <errno.h>
# include <sys/ioctl.h>
# include <sys/wait.h>
# include <signal.h>
# include <locale.h>
# include "spiceterm.h"
2013-08-21 14:58:20 +04:00
# include <glib.h>
2013-08-06 12:58:17 +04:00
# include <spice.h>
# include <spice/enums.h>
# include <spice/macros.h>
# include <spice/qxl_dev.h>
2013-08-21 14:00:42 +04:00
# include <gdk/gdkkeysyms.h>
2013-08-06 12:58:17 +04:00
2013-09-11 13:57:01 +04:00
# include "event_loop.h"
2013-09-11 09:44:47 +04:00
# include "translations.h"
2013-09-10 15:08:47 +04:00
2013-09-11 14:56:28 +04:00
static int debug = 0 ;
2013-09-12 09:16:03 +04:00
2013-09-11 14:56:28 +04:00
# define DPRINTF(x, format, ...) { \
if ( x < = debug ) { \
printf ( " %s: " format " \n " , __FUNCTION__ , # # __VA_ARGS__ ) ; \
} \
}
2013-08-06 12:58:17 +04:00
# define TERM "xterm"
# define TERMIDCODE "[?1;2c" // vt100 ID
# define CHECK_ARGC(argc,argv,i) if (i >= argc-1) { \
2013-09-11 14:56:28 +04:00
fprintf ( stderr , " ERROR: not enough arguments for: %s \n " , argv [ i ] ) ; \
print_usage ( NULL ) ; \
2013-08-06 12:58:17 +04:00
exit ( 1 ) ; \
}
/* these colours are from linux kernel drivers/char/vt.c */
unsigned char color_table [ ] = { 0 , 4 , 2 , 6 , 1 , 5 , 3 , 7 ,
8 , 12 , 10 , 14 , 9 , 13 , 11 , 15 } ;
static void
2013-09-12 09:16:03 +04:00
print_usage ( const char * msg )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
if ( msg ) { fprintf ( stderr , " ERROR: %s \n " , msg ) ; }
fprintf ( stderr , " USAGE: spiceterm [spiceopts] [-c command [args]] \n " ) ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 15:15:53 +04:00
draw_char_at ( spiceTerm * vt , int x , int y , gunichar2 ch , TextAttributes attrib )
2013-08-06 12:58:17 +04:00
{
2013-08-21 09:43:55 +04:00
if ( x < 0 | | y < 0 | | x > = vt - > width | | y > = vt - > height ) {
return ;
2013-08-06 12:58:17 +04:00
}
2013-09-11 13:57:01 +04:00
spice_screen_draw_char ( vt - > screen , x , y , ch , attrib ) ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_update_xy ( spiceTerm * vt , int x , int y )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
if ( x < 0 | | y < 0 | | x > = vt - > width | | y > = vt - > height ) { return ; }
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
int y1 = ( vt - > y_base + y ) % vt - > total_height ;
int y2 = y1 - vt - > y_displ ;
if ( y2 < 0 ) {
y2 + = vt - > total_height ;
}
if ( y2 < vt - > height ) {
TextCell * c = & vt - > cells [ y1 * vt - > width + x ] ;
draw_char_at ( vt , x , y2 , c - > ch , c - > attrib ) ;
}
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_clear_xy ( spiceTerm * vt , int x , int y )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
if ( x < 0 | | y < 0 | | x > = vt - > width | | y > = vt - > height ) { return ; }
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
int y1 = ( vt - > y_base + y ) % vt - > total_height ;
int y2 = y1 - vt - > y_displ ;
if ( y2 < 0 ) {
y2 + = vt - > total_height ;
}
if ( y2 < vt - > height ) {
TextCell * c = & vt - > cells [ y1 * vt - > width + x ] ;
c - > ch = ' ' ;
c - > attrib = vt - > default_attrib ;
c - > attrib . fgcol = vt - > cur_attrib . fgcol ;
c - > attrib . bgcol = vt - > cur_attrib . bgcol ;
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
}
2013-08-06 12:58:17 +04:00
}
2013-09-13 11:53:24 +04:00
void
spiceterm_toggle_marked_cell ( spiceTerm * vt , int pos )
{
int x = ( pos % vt - > width ) ;
int y = ( pos / vt - > width ) ;
if ( x < 0 | | y < 0 | | x > = vt - > width | | y > = vt - > height ) { return ; }
int y1 = ( vt - > y_base + y ) % vt - > total_height ;
int y2 = y1 - vt - > y_displ ;
if ( y2 < 0 ) {
y2 + = vt - > total_height ;
}
if ( y2 < vt - > height ) {
TextCell * c = & vt - > cells [ y1 * vt - > width + x ] ;
c - > attrib . selected = c - > attrib . selected ? 0 : 1 ;
spice_screen_draw_char ( vt - > screen , x , y , c - > ch , c - > attrib ) ;
}
}
2013-08-06 12:58:17 +04:00
static void
2013-09-11 09:20:40 +04:00
spiceterm_show_cursor ( spiceTerm * vt , int show )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int x = vt - > cx ;
if ( x > = vt - > width ) {
x = vt - > width - 1 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
int y1 = ( vt - > y_base + vt - > cy ) % vt - > total_height ;
int y = y1 - vt - > y_displ ;
if ( y < 0 ) {
y + = vt - > total_height ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( y < vt - > height ) {
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
TextCell * c = & vt - > cells [ y1 * vt - > width + x ] ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( show ) {
TextAttributes attrib = vt - > default_attrib ;
attrib . invers = ! ( attrib . invers ) ; /* invert fg and bg */
draw_char_at ( vt , x , y , c - > ch , attrib ) ;
} else {
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
}
2013-08-06 12:58:17 +04:00
}
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_refresh ( spiceTerm * vt )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int x , y , y1 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
y1 = vt - > y_displ ;
for ( y = 0 ; y < vt - > height ; y + + ) {
TextCell * c = vt - > cells + y1 * vt - > width ;
for ( x = 0 ; x < vt - > width ; x + + ) {
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
c + + ;
}
if ( + + y1 = = vt - > total_height )
y1 = 0 ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
spiceterm_show_cursor ( vt , 1 ) ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_scroll_down ( spiceTerm * vt , int top , int bottom , int lines )
2013-08-06 12:58:17 +04:00
{
2013-08-21 16:30:16 +04:00
if ( ( top + lines ) > = bottom ) {
lines = bottom - top - 1 ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
if ( top < 0 | | bottom > vt - > height | | top > = bottom | | lines < 1 ) {
return ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
int i ;
for ( i = bottom - top - lines - 1 ; i > = 0 ; i - - ) {
int src = ( ( vt - > y_base + top + i ) % vt - > total_height ) * vt - > width ;
int dst = ( ( vt - > y_base + top + lines + i ) % vt - > total_height ) * vt - > width ;
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
memmove ( vt - > cells + dst , vt - > cells + src , vt - > width * sizeof ( TextCell ) ) ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
for ( i = 0 ; i < lines ; i + + ) {
int j ;
TextCell * c = vt - > cells + ( ( vt - > y_base + top + i ) % vt - > total_height ) * vt - > width ;
for ( j = 0 ; j < vt - > width ; j + + ) {
c - > attrib = vt - > default_attrib ;
c - > ch = ' ' ;
c + + ;
}
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
int h = lines * 16 ;
int y0 = top * 16 ;
int y1 = y0 + h ;
int y2 = bottom * 16 ;
2013-08-06 12:58:17 +04:00
2013-09-11 13:57:01 +04:00
spice_screen_scroll ( vt - > screen , 0 , y1 , vt - > screen - > primary_width , y2 , 0 , y0 ) ;
spice_screen_clear ( vt - > screen , 0 , y0 , vt - > screen - > primary_width , y1 ) ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_scroll_up ( spiceTerm * vt , int top , int bottom , int lines , int moveattr )
2013-08-06 12:58:17 +04:00
{
2013-08-21 16:30:16 +04:00
if ( ( top + lines ) > = bottom ) {
lines = bottom - top - 1 ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
if ( top < 0 | | bottom > vt - > height | | top > = bottom | | lines < 1 ) {
return ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
int h = lines * 16 ;
int y0 = top * 16 ;
int y1 = ( top + lines ) * 16 ;
int y2 = bottom * 16 ;
2013-08-06 12:58:17 +04:00
2013-09-11 13:57:01 +04:00
spice_screen_scroll ( vt - > screen , 0 , y0 , vt - > screen - > primary_width , y2 - h , 0 , y1 ) ;
spice_screen_clear ( vt - > screen , 0 , y2 - h , vt - > screen - > primary_width , y2 ) ;
2013-09-12 09:16:03 +04:00
2013-08-21 16:30:16 +04:00
if ( ! moveattr ) {
return ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
// move attributes
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
int i ;
for ( i = 0 ; i < ( bottom - top - lines ) ; i + + ) {
int dst = ( ( vt - > y_base + top + i ) % vt - > total_height ) * vt - > width ;
int src = ( ( vt - > y_base + top + lines + i ) % vt - > total_height ) * vt - > width ;
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
memmove ( vt - > cells + dst , vt - > cells + src , vt - > width * sizeof ( TextCell ) ) ;
}
2013-08-06 12:58:17 +04:00
2013-08-21 16:30:16 +04:00
for ( i = 1 ; i < = lines ; i + + ) {
int j ;
TextCell * c = vt - > cells + ( ( vt - > y_base + bottom - i ) % vt - > total_height ) * vt - > width ;
for ( j = 0 ; j < vt - > width ; j + + ) {
c - > attrib = vt - > default_attrib ;
c - > ch = ' ' ;
c + + ;
}
2013-08-06 12:58:17 +04:00
}
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_virtual_scroll ( spiceTerm * vt , int lines )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
if ( vt - > altbuf | | lines = = 0 ) return ;
if ( lines < 0 ) {
lines = - lines ;
int i = vt - > scroll_height ;
if ( i > vt - > total_height - vt - > height )
i = vt - > total_height - vt - > height ;
int y1 = vt - > y_base - i ;
if ( y1 < 0 )
y1 + = vt - > total_height ;
for ( i = 0 ; i < lines ; i + + ) {
if ( vt - > y_displ = = y1 ) break ;
if ( - - vt - > y_displ < 0 ) {
vt - > y_displ = vt - > total_height - 1 ;
}
}
} else {
int i ;
for ( i = 0 ; i < lines ; i + + ) {
if ( vt - > y_displ = = vt - > y_base ) break ;
if ( + + vt - > y_displ = = vt - > total_height ) {
vt - > y_displ = 0 ;
}
}
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
spiceterm_refresh ( vt ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
2013-08-06 12:58:17 +04:00
static void
2013-09-11 09:20:40 +04:00
spiceterm_respond_esc ( spiceTerm * vt , const char * esc )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int len = strlen ( esc ) ;
int i ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > ibuf_count < ( IBUFSIZE - 1 - len ) ) {
vt - > ibuf [ vt - > ibuf_count + + ] = 27 ;
for ( i = 0 ; i < len ; i + + ) {
vt - > ibuf [ vt - > ibuf_count + + ] = esc [ i ] ;
}
2013-08-06 12:58:17 +04:00
}
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_put_lf ( spiceTerm * vt )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
if ( vt - > cy + 1 = = vt - > region_bottom ) {
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > altbuf | | vt - > region_top ! = 0 | | vt - > region_bottom ! = vt - > height ) {
spiceterm_scroll_up ( vt , vt - > region_top , vt - > region_bottom , 1 , 1 ) ;
return ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > y_displ = = vt - > y_base ) {
spiceterm_scroll_up ( vt , vt - > region_top , vt - > region_bottom , 1 , 0 ) ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > y_displ = = vt - > y_base ) {
if ( + + vt - > y_displ = = vt - > total_height ) {
vt - > y_displ = 0 ;
}
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( + + vt - > y_base = = vt - > total_height ) {
vt - > y_base = 0 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > scroll_height < vt - > total_height ) {
vt - > scroll_height + + ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
int y1 = ( vt - > y_base + vt - > height - 1 ) % vt - > total_height ;
TextCell * c = & vt - > cells [ y1 * vt - > width ] ;
int x ;
for ( x = 0 ; x < vt - > width ; x + + ) {
c - > ch = ' ' ;
c - > attrib = vt - > default_attrib ;
c + + ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
// fprintf (stderr, "BASE: %d DISPLAY %d\n", vt->y_base, vt->y_displ);
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
} else if ( vt - > cy < vt - > height - 1 ) {
vt - > cy + = 1 ;
}
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_csi_m ( spiceTerm * vt )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int i ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
for ( i = 0 ; i < vt - > esc_count ; i + + ) {
switch ( vt - > esc_buf [ i ] ) {
case 0 : /* reset all console attributes to default */
vt - > cur_attrib = vt - > default_attrib ;
break ;
case 1 :
vt - > cur_attrib . bold = 1 ;
break ;
case 4 :
vt - > cur_attrib . uline = 1 ;
break ;
case 5 :
vt - > cur_attrib . blink = 1 ;
break ;
case 7 :
vt - > cur_attrib . invers = 1 ;
break ;
case 8 :
vt - > cur_attrib . unvisible = 1 ;
break ;
case 10 :
vt - > cur_enc = LAT1_MAP ;
// fixme: dispaly controls = 0 ?
// fixme: toggle meta = 0 ?
break ;
case 11 :
vt - > cur_enc = IBMPC_MAP ;
// fixme: dispaly controls = 1 ?
// fixme: toggle meta = 0 ?
break ;
case 12 :
vt - > cur_enc = IBMPC_MAP ;
// fixme: dispaly controls = 1 ?
// fixme: toggle meta = 1 ?
break ;
case 22 :
vt - > cur_attrib . bold = 0 ;
break ;
case 24 :
vt - > cur_attrib . uline = 0 ;
break ;
case 25 :
vt - > cur_attrib . blink = 0 ;
break ;
case 27 :
vt - > cur_attrib . invers = 0 ;
break ;
case 28 :
vt - > cur_attrib . unvisible = 0 ;
break ;
case 30 :
case 31 :
case 32 :
case 33 :
case 34 :
case 35 :
case 36 :
case 37 :
/* set foreground color */
vt - > cur_attrib . fgcol = color_table [ vt - > esc_buf [ i ] - 30 ] ;
break ;
case 38 :
/* reset color to default, enable underline */
vt - > cur_attrib . fgcol = vt - > default_attrib . fgcol ;
vt - > cur_attrib . uline = 1 ;
break ;
case 39 :
/* reset color to default, disable underline */
vt - > cur_attrib . fgcol = vt - > default_attrib . fgcol ;
vt - > cur_attrib . uline = 0 ;
break ;
case 40 :
case 41 :
case 42 :
case 43 :
case 44 :
case 45 :
case 46 :
case 47 :
/* set background color */
vt - > cur_attrib . bgcol = color_table [ vt - > esc_buf [ i ] - 40 ] ;
break ;
case 49 :
/* reset background color */
vt - > cur_attrib . bgcol = vt - > default_attrib . bgcol ;
break ;
default :
fprintf ( stderr , " unhandled ESC[%d m code \n " , vt - > esc_buf [ i ] ) ;
//fixme: implement
}
}
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_save_cursor ( spiceTerm * vt )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
vt - > cx_saved = vt - > cx ;
vt - > cy_saved = vt - > cy ;
vt - > cur_attrib_saved = vt - > cur_attrib ;
vt - > charset_saved = vt - > charset ;
vt - > g0enc_saved = vt - > g0enc ;
vt - > g1enc_saved = vt - > g1enc ;
vt - > cur_enc_saved = vt - > cur_enc ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_restore_cursor ( spiceTerm * vt )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
vt - > cx = vt - > cx_saved ;
vt - > cy = vt - > cy_saved ;
vt - > cur_attrib = vt - > cur_attrib_saved ;
vt - > charset = vt - > charset_saved ;
vt - > g0enc = vt - > g0enc_saved ;
vt - > g1enc = vt - > g1enc_saved ;
vt - > cur_enc = vt - > cur_enc_saved ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_set_alternate_buffer ( spiceTerm * vt , int on_off )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int x , y ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > y_displ = vt - > y_base ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( on_off ) {
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > altbuf ) return ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > altbuf = 1 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
/* alternate buffer & cursor */
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
spiceterm_save_cursor ( vt ) ;
/* save screen to altcels */
for ( y = 0 ; y < vt - > height ; y + + ) {
int y1 = ( vt - > y_base + y ) % vt - > total_height ;
for ( x = 0 ; x < vt - > width ; x + + ) {
vt - > altcells [ y * vt - > width + x ] = vt - > cells [ y1 * vt - > width + x ] ;
}
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
/* clear screen */
for ( y = 0 ; y < = vt - > height ; y + + ) {
for ( x = 0 ; x < vt - > width ; x + + ) {
spiceterm_clear_xy ( vt , x , y ) ;
}
}
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
} else {
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > altbuf = = 0 ) return ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > altbuf = 0 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
/* restore saved data */
for ( y = 0 ; y < vt - > height ; y + + ) {
int y1 = ( vt - > y_base + y ) % vt - > total_height ;
for ( x = 0 ; x < vt - > width ; x + + ) {
vt - > cells [ y1 * vt - > width + x ] = vt - > altcells [ y * vt - > width + x ] ;
}
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
spiceterm_restore_cursor ( vt ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
spiceterm_refresh ( vt ) ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_set_mode ( spiceTerm * vt , int on_off )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int i ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
for ( i = 0 ; i < = vt - > esc_count ; i + + ) {
if ( vt - > esc_ques ) { /* DEC private modes set/reset */
switch ( vt - > esc_buf [ i ] ) {
case 10 : /* X11 mouse reporting on/off */
2013-09-12 17:36:37 +04:00
case 1000 : /* SET_VT200_MOUSE */
case 1002 : /* xterm SET_BTN_EVENT_MOUSE */
2013-09-12 09:16:03 +04:00
vt - > report_mouse = on_off ;
break ;
case 1049 : /* start/end special app mode (smcup/rmcup) */
spiceterm_set_alternate_buffer ( vt , on_off ) ;
break ;
case 25 : /* Cursor on/off */
2013-09-12 17:36:37 +04:00
case 9 : /* X10 mouse reporting on/off */
2013-09-12 09:16:03 +04:00
case 6 : /* Origin relative/absolute */
case 1 : /* Cursor keys in appl mode*/
case 5 : /* Inverted screen on/off */
case 7 : /* Autowrap on/off */
case 8 : /* Autorepeat on/off */
break ;
2013-09-12 17:36:37 +04:00
}
2013-09-12 09:16:03 +04:00
} else { /* ANSI modes set/reset */
2013-09-12 17:36:37 +04:00
//g_assert_not_reached();
2013-09-12 09:16:03 +04:00
/* fixme: implement me */
}
2013-08-06 12:58:17 +04:00
}
}
static void
2013-09-11 09:20:40 +04:00
spiceterm_gotoxy ( spiceTerm * vt , int x , int y )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
/* verify all boundaries */
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( x < 0 ) {
x = 0 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( x > = vt - > width ) {
x = vt - > width - 1 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > cx = x ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( y < 0 ) {
y = 0 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( y > = vt - > height ) {
y = vt - > height - 1 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > cy = y ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 11:26:44 +04:00
static void
debug_print_escape_buffer ( spiceTerm * vt , const char * func , const char * prefix ,
const char * qes , gunichar2 ch )
{
if ( debug > = 1 ) {
if ( vt - > esc_count = = 0 ) {
printf ( " %s:%s ESC[%s%c \n " , func , prefix , qes , ch ) ;
} else if ( vt - > esc_count = = 1 ) {
printf ( " %s:%s ESC[%s%d%c \n " , func , prefix , qes , vt - > esc_buf [ 0 ] , ch ) ;
} else {
int i ;
printf ( " %s:%s ESC[%s%d " , func , prefix , qes , vt - > esc_buf [ 0 ] ) ;
for ( i = 1 ; i < vt - > esc_count ; i + + ) {
printf ( " ;%d " , vt - > esc_buf [ i ] ) ;
}
printf ( " %c \n " , ch ) ;
}
}
}
2013-08-06 12:58:17 +04:00
enum { ESnormal , ESesc , ESsquare , ESgetpars , ESgotpars , ESfunckey ,
EShash , ESsetG0 , ESsetG1 , ESpercent , ESignore , ESnonstd ,
ESpalette , ESidquery , ESosc1 , ESosc2 } ;
static void
2013-09-11 15:15:53 +04:00
spiceterm_putchar ( spiceTerm * vt , gunichar2 ch )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int x , y , i , c ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( debug & & ! vt - > tty_state ) {
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " CHAR:%2d: %4x '%c' (cur_enc %d) %d %d " ,
2013-09-12 09:16:03 +04:00
vt - > tty_state , ch , ch , vt - > cur_enc , vt - > cx , vt - > cy ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
switch ( vt - > tty_state ) {
case ESesc :
vt - > tty_state = ESnormal ;
switch ( ch ) {
case ' [ ' :
vt - > tty_state = ESsquare ;
break ;
case ' ] ' :
vt - > tty_state = ESnonstd ;
break ;
case ' % ' :
vt - > tty_state = ESpercent ;
break ;
case ' 7 ' :
spiceterm_save_cursor ( vt ) ;
break ;
case ' 8 ' :
spiceterm_restore_cursor ( vt ) ;
break ;
case ' ( ' :
vt - > tty_state = ESsetG0 ; // SET G0
break ;
case ' ) ' :
vt - > tty_state = ESsetG1 ; // SET G1
break ;
case ' M ' :
/* cursor up (ri) */
if ( vt - > cy = = vt - > region_top )
spiceterm_scroll_down ( vt , vt - > region_top , vt - > region_bottom , 1 ) ;
else if ( vt - > cy > 0 ) {
vt - > cy - - ;
}
break ;
case ' > ' :
/* numeric keypad - ignored */
break ;
case ' = ' :
/* appl. keypad - ignored */
break ;
default :
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " got unhandled ESC%c %d " , ch , ch ) ;
2013-09-12 09:16:03 +04:00
break ;
}
break ;
case ESnonstd : /* Operating System Controls */
vt - > tty_state = ESnormal ;
switch ( ch ) {
case ' P ' : /* palette escape sequence */
for ( i = 0 ; i < MAX_ESC_PARAMS ; i + + ) {
vt - > esc_buf [ i ] = 0 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > esc_count = 0 ;
vt - > tty_state = ESpalette ;
break ;
case ' R ' : /* reset palette */
// fixme: reset_palette(vc);
break ;
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 4 ' :
vt - > osc_cmd = ch ;
vt - > osc_textbuf [ 0 ] = 0 ;
vt - > tty_state = ESosc1 ;
break ;
default :
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " got unhandled OSC %c " , ch ) ;
2013-09-12 09:16:03 +04:00
vt - > tty_state = ESnormal ;
break ;
}
break ;
case ESosc1 :
vt - > tty_state = ESnormal ;
if ( ch = = ' ; ' ) {
vt - > tty_state = ESosc2 ;
} else {
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " got illegal OSC sequence " ) ;
2013-09-12 09:16:03 +04:00
}
break ;
case ESosc2 :
if ( ch ! = 0x9c & & ch ! = 7 ) {
int i = 0 ;
while ( vt - > osc_textbuf [ i ] ) i + + ;
vt - > osc_textbuf [ i + + ] = ch ;
vt - > osc_textbuf [ i ] = 0 ;
} else {
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " OSC:%c:%s " , vt - > osc_cmd , vt - > osc_textbuf ) ;
2013-09-12 09:16:03 +04:00
vt - > tty_state = ESnormal ;
}
break ;
case ESpalette :
if ( ( ch > = ' 0 ' & & ch < = ' 9 ' ) | | ( ch > = ' A ' & & ch < = ' F ' )
| | ( ch > = ' a ' & & ch < = ' f ' ) ) {
vt - > esc_buf [ vt - > esc_count + + ] = ( ch > ' 9 ' ? ( ch & 0xDF ) - ' A ' + 10 : ch - ' 0 ' ) ;
if ( vt - > esc_count = = 7 ) {
// fixme: this does not work - please test
/*
rfbColourMap * cmap = & vt - > screen - > colourMap ;
int i = color_table [ vt - > esc_buf [ 0 ] ] * 3 , j = 1 ;
cmap - > data . bytes [ i ] = 16 * vt - > esc_buf [ j + + ] ;
cmap - > data . bytes [ i + + ] + = vt - > esc_buf [ j + + ] ;
cmap - > data . bytes [ i ] = 16 * vt - > esc_buf [ j + + ] ;
cmap - > data . bytes [ i + + ] + = vt - > esc_buf [ j + + ] ;
cmap - > data . bytes [ i ] = 16 * vt - > esc_buf [ j + + ] ;
cmap - > data . bytes [ i ] + = vt - > esc_buf [ j ] ;
*/
//set_palette(vc); ?
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
vt - > tty_state = ESnormal ;
}
} else
vt - > tty_state = ESnormal ;
break ;
case ESsquare :
for ( i = 0 ; i < MAX_ESC_PARAMS ; i + + ) {
vt - > esc_buf [ i ] = 0 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > esc_count = 0 ;
vt - > esc_has_par = 0 ;
vt - > tty_state = ESgetpars ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( ch = = ' > ' ) {
vt - > tty_state = ESidquery ;
break ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( ( vt - > esc_ques = ( ch = = ' ? ' ) ) ) {
break ;
}
case ESgetpars :
if ( ch > = ' 0 ' & & ch < = ' 9 ' ) {
vt - > esc_has_par = 1 ;
if ( vt - > esc_count < MAX_ESC_PARAMS ) {
vt - > esc_buf [ vt - > esc_count ] = vt - > esc_buf [ vt - > esc_count ] * 10 + ch - ' 0 ' ;
}
break ;
} else if ( ch = = ' ; ' ) {
vt - > esc_count + + ;
break ;
2013-09-11 14:56:28 +04:00
} else {
2013-09-12 09:16:03 +04:00
if ( vt - > esc_has_par ) {
vt - > esc_count + + ;
}
vt - > tty_state = ESgotpars ;
}
case ESgotpars :
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
vt - > tty_state = ESnormal ;
char * qes = vt - > esc_ques ? " ? " : " " ;
if ( debug ) {
2013-09-12 11:26:44 +04:00
debug_print_escape_buffer ( vt , __func__ , " " , qes , ch ) ;
2013-09-11 14:56:28 +04:00
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
switch ( ch ) {
case ' h ' :
2013-09-12 17:36:37 +04:00
spiceterm_set_mode ( vt , 1 ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' l ' :
2013-09-12 17:36:37 +04:00
spiceterm_set_mode ( vt , 0 ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' m ' :
if ( ! vt - > esc_count ) {
vt - > esc_count + + ; // default parameter 0
}
spiceterm_csi_m ( vt ) ;
break ;
case ' n ' :
/* report cursor position */
/* TODO: send ESC[row;colR */
break ;
case ' A ' :
/* move cursor up */
if ( vt - > esc_buf [ 0 ] = = 0 ) {
vt - > esc_buf [ 0 ] = 1 ;
}
vt - > cy - = vt - > esc_buf [ 0 ] ;
if ( vt - > cy < 0 ) {
vt - > cy = 0 ;
}
break ;
case ' B ' :
case ' e ' :
/* move cursor down */
if ( vt - > esc_buf [ 0 ] = = 0 ) {
vt - > esc_buf [ 0 ] = 1 ;
}
vt - > cy + = vt - > esc_buf [ 0 ] ;
if ( vt - > cy > = vt - > height ) {
vt - > cy = vt - > height - 1 ;
}
break ;
case ' C ' :
case ' a ' :
/* move cursor right */
if ( vt - > esc_buf [ 0 ] = = 0 ) {
vt - > esc_buf [ 0 ] = 1 ;
}
vt - > cx + = vt - > esc_buf [ 0 ] ;
if ( vt - > cx > = vt - > width ) {
vt - > cx = vt - > width - 1 ;
}
break ;
case ' D ' :
/* move cursor left */
if ( vt - > esc_buf [ 0 ] = = 0 ) {
vt - > esc_buf [ 0 ] = 1 ;
}
vt - > cx - = vt - > esc_buf [ 0 ] ;
if ( vt - > cx < 0 ) {
vt - > cx = 0 ;
}
break ;
case ' G ' :
case ' ` ' :
/* move cursor to column */
spiceterm_gotoxy ( vt , vt - > esc_buf [ 0 ] - 1 , vt - > cy ) ;
break ;
case ' d ' :
/* move cursor to row */
spiceterm_gotoxy ( vt , vt - > cx , vt - > esc_buf [ 0 ] - 1 ) ;
break ;
case ' f ' :
case ' H ' :
/* move cursor to row, column */
spiceterm_gotoxy ( vt , vt - > esc_buf [ 1 ] - 1 , vt - > esc_buf [ 0 ] - 1 ) ;
break ;
case ' J ' :
switch ( vt - > esc_buf [ 0 ] ) {
case 0 :
/* clear to end of screen */
for ( y = vt - > cy ; y < vt - > height ; y + + ) {
for ( x = 0 ; x < vt - > width ; x + + ) {
if ( y = = vt - > cy & & x < vt - > cx ) {
continue ;
}
spiceterm_clear_xy ( vt , x , y ) ;
}
}
break ;
case 1 :
/* clear from beginning of screen */
for ( y = 0 ; y < = vt - > cy ; y + + ) {
for ( x = 0 ; x < vt - > width ; x + + ) {
if ( y = = vt - > cy & & x > vt - > cx ) {
break ;
}
spiceterm_clear_xy ( vt , x , y ) ;
}
}
break ;
case 2 :
/* clear entire screen */
for ( y = 0 ; y < = vt - > height ; y + + ) {
for ( x = 0 ; x < vt - > width ; x + + ) {
spiceterm_clear_xy ( vt , x , y ) ;
}
}
break ;
}
break ;
case ' K ' :
switch ( vt - > esc_buf [ 0 ] ) {
case 0 :
/* clear to eol */
for ( x = vt - > cx ; x < vt - > width ; x + + ) {
spiceterm_clear_xy ( vt , x , vt - > cy ) ;
}
break ;
case 1 :
/* clear from beginning of line */
for ( x = 0 ; x < = vt - > cx ; x + + ) {
spiceterm_clear_xy ( vt , x , vt - > cy ) ;
}
break ;
case 2 :
/* clear entire line */
for ( x = 0 ; x < vt - > width ; x + + ) {
spiceterm_clear_xy ( vt , x , vt - > cy ) ;
}
break ;
}
break ;
case ' L ' :
/* insert line */
c = vt - > esc_buf [ 0 ] ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( c > vt - > height - vt - > cy )
c = vt - > height - vt - > cy ;
else if ( ! c )
c = 1 ;
spiceterm_scroll_down ( vt , vt - > cy , vt - > region_bottom , c ) ;
break ;
case ' M ' :
/* delete line */
c = vt - > esc_buf [ 0 ] ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( c > vt - > height - vt - > cy )
c = vt - > height - vt - > cy ;
else if ( ! c )
c = 1 ;
spiceterm_scroll_up ( vt , vt - > cy , vt - > region_bottom , c , 1 ) ;
break ;
case ' T ' :
/* scroll down */
c = vt - > esc_buf [ 0 ] ;
if ( ! c ) c = 1 ;
spiceterm_scroll_down ( vt , vt - > region_top , vt - > region_bottom , c ) ;
break ;
case ' S ' :
/* scroll up */
c = vt - > esc_buf [ 0 ] ;
if ( ! c ) c = 1 ;
spiceterm_scroll_up ( vt , vt - > region_top , vt - > region_bottom , c , 1 ) ;
break ;
case ' P ' :
/* delete c character */
c = vt - > esc_buf [ 0 ] ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( c > vt - > width - vt - > cx )
c = vt - > width - vt - > cx ;
else if ( ! c )
c = 1 ;
for ( x = vt - > cx ; x < vt - > width - c ; x + + ) {
int y1 = ( vt - > y_base + vt - > cy ) % vt - > total_height ;
TextCell * dst = & vt - > cells [ y1 * vt - > width + x ] ;
TextCell * src = dst + c ;
* dst = * src ;
spiceterm_update_xy ( vt , x + c , vt - > cy ) ;
src - > ch = ' ' ;
src - > attrib = vt - > default_attrib ;
spiceterm_update_xy ( vt , x , vt - > cy ) ;
}
break ;
case ' s ' :
/* save cursor position */
spiceterm_save_cursor ( vt ) ;
break ;
case ' u ' :
/* restore cursor position */
spiceterm_restore_cursor ( vt ) ;
break ;
case ' X ' :
/* erase c characters */
c = vt - > esc_buf [ 0 ] ;
if ( ! c ) c = 1 ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( c > ( vt - > width - vt - > cx ) ) c = vt - > width - vt - > cx ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
for ( i = 0 ; i < c ; i + + ) {
spiceterm_clear_xy ( vt , vt - > cx + i , vt - > cy ) ;
}
break ;
case ' @ ' :
/* insert c character */
c = vt - > esc_buf [ 0 ] ;
if ( c > ( vt - > width - vt - > cx ) ) {
c = vt - > width - vt - > cx ;
}
if ( ! c ) c = 1 ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
for ( x = vt - > width - c ; x > = vt - > cx ; x - - ) {
int y1 = ( vt - > y_base + vt - > cy ) % vt - > total_height ;
TextCell * src = & vt - > cells [ y1 * vt - > width + x ] ;
TextCell * dst = src + c ;
* dst = * src ;
spiceterm_update_xy ( vt , x + c , vt - > cy ) ;
src - > ch = ' ' ;
src - > attrib = vt - > cur_attrib ;
spiceterm_update_xy ( vt , x , vt - > cy ) ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
break ;
case ' r ' :
/* set region */
if ( ! vt - > esc_buf [ 0 ] )
vt - > esc_buf [ 0 ] + + ;
if ( ! vt - > esc_buf [ 1 ] )
vt - > esc_buf [ 1 ] = vt - > height ;
/* Minimum allowed region is 2 lines */
if ( vt - > esc_buf [ 0 ] < vt - > esc_buf [ 1 ] & &
vt - > esc_buf [ 1 ] < = vt - > height ) {
vt - > region_top = vt - > esc_buf [ 0 ] - 1 ;
vt - > region_bottom = vt - > esc_buf [ 1 ] ;
vt - > cx = 0 ;
vt - > cy = vt - > region_top ;
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " set region %d %d " , vt - > region_top , vt - > region_bottom ) ;
2013-09-12 09:16:03 +04:00
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
break ;
default :
if ( debug ) {
2013-09-12 11:26:44 +04:00
debug_print_escape_buffer ( vt , __func__ , " unhandled escape " , qes , ch ) ;
2013-09-12 09:16:03 +04:00
}
break ;
}
vt - > esc_ques = 0 ;
break ;
case ESsetG0 : // Set G0
vt - > tty_state = ESnormal ;
if ( ch = = ' 0 ' )
vt - > g0enc = GRAF_MAP ;
else if ( ch = = ' B ' )
vt - > g0enc = LAT1_MAP ;
else if ( ch = = ' U ' )
vt - > g0enc = IBMPC_MAP ;
else if ( ch = = ' K ' )
vt - > g0enc = USER_MAP ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > charset = = 0 )
vt - > cur_enc = vt - > g0enc ;
break ;
case ESsetG1 : // Set G1
vt - > tty_state = ESnormal ;
if ( ch = = ' 0 ' )
vt - > g1enc = GRAF_MAP ;
else if ( ch = = ' B ' )
vt - > g1enc = LAT1_MAP ;
else if ( ch = = ' U ' )
vt - > g1enc = IBMPC_MAP ;
else if ( ch = = ' K ' )
vt - > g1enc = USER_MAP ;
if ( vt - > charset = = 1 )
vt - > cur_enc = vt - > g1enc ;
break ;
case ESidquery : // vt100 query id
vt - > tty_state = ESnormal ;
if ( ch = = ' c ' ) {
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " ESC[>c Query term ID " ) ;
2013-09-12 09:16:03 +04:00
spiceterm_respond_esc ( vt , TERMIDCODE ) ;
2013-09-12 17:36:37 +04:00
}
2013-09-12 09:16:03 +04:00
break ;
case ESpercent :
vt - > tty_state = ESnormal ;
switch ( ch ) {
case ' @ ' : /* defined in ISO 2022 */
vt - > utf8 = 0 ;
break ;
case ' G ' : /* prelim official escape code */
case ' 8 ' : /* retained for compatibility */
vt - > utf8 = 1 ;
break ;
}
break ;
default : // ESnormal
vt - > tty_state = ESnormal ;
switch ( ch ) {
case 0 :
break ;
case 7 : /* alert aka. bell */
// fixme:
//rfbSendBell(vt->screen);
break ;
case 8 : /* backspace */
if ( vt - > cx > 0 )
vt - > cx - - ;
break ;
case 9 : /* tabspace */
if ( vt - > cx + ( 8 - ( vt - > cx % 8 ) ) > vt - > width ) {
vt - > cx = 0 ;
spiceterm_put_lf ( vt ) ;
} else {
vt - > cx = vt - > cx + ( 8 - ( vt - > cx % 8 ) ) ;
}
break ;
case 10 : /* LF,*/
case 11 : /* VT */
case 12 : /* FF */
spiceterm_put_lf ( vt ) ;
break ;
case 13 : /* carriage return */
vt - > cx = 0 ;
break ;
case 14 :
/* SI (shift in), select character set 1 */
vt - > charset = 1 ;
vt - > cur_enc = vt - > g1enc ;
/* fixme: display controls = 1 */
break ;
case 15 :
/* SO (shift out), select character set 0 */
vt - > charset = 0 ;
vt - > cur_enc = vt - > g0enc ;
/* fixme: display controls = 0 */
break ;
case 27 : /* esc */
vt - > tty_state = ESesc ;
break ;
case 127 : /* delete */
/* ignore */
break ;
case 128 + 27 : /* csi */
vt - > tty_state = ESsquare ;
break ;
default :
if ( vt - > cx > = vt - > width ) {
/* line wrap */
vt - > cx = 0 ;
spiceterm_put_lf ( vt ) ;
}
int y1 = ( vt - > y_base + vt - > cy ) % vt - > total_height ;
TextCell * c = & vt - > cells [ y1 * vt - > width + vt - > cx ] ;
c - > attrib = vt - > cur_attrib ;
c - > ch = ch ;
spiceterm_update_xy ( vt , vt - > cx , vt - > cy ) ;
vt - > cx + + ;
break ;
}
break ;
2013-08-06 12:58:17 +04:00
}
}
static int
2013-09-11 09:20:40 +04:00
spiceterm_puts ( spiceTerm * vt , const char * buf , int len )
2013-08-06 12:58:17 +04:00
{
2013-09-11 15:15:53 +04:00
gunichar2 tc ;
2013-08-06 12:58:17 +04:00
2013-09-11 09:20:40 +04:00
spiceterm_show_cursor ( vt , 0 ) ;
2013-08-06 12:58:17 +04:00
while ( len ) {
2013-09-12 09:16:03 +04:00
unsigned char c = * buf ;
len - - ;
buf + + ;
if ( vt - > tty_state ! = ESnormal ) {
// never translate escape sequence
tc = c ;
} else if ( vt - > utf8 & & ! vt - > cur_enc ) {
if ( c & 0x80 ) { // utf8 multi-byte sequence
if ( vt - > utf_count > 0 & & ( c & 0xc0 ) = = 0x80 ) {
// inside UTF8 sequence
vt - > utf_char = ( vt - > utf_char < < 6 ) | ( c & 0x3f ) ;
vt - > utf_count - - ;
if ( vt - > utf_count = = 0 ) {
tc = vt - > utf_char ;
} else {
continue ;
}
} else {
// first char of a UTF8 sequence
if ( ( c & 0xe0 ) = = 0xc0 ) {
vt - > utf_count = 1 ;
vt - > utf_char = ( c & 0x1f ) ;
} else if ( ( c & 0xf0 ) = = 0xe0 ) {
vt - > utf_count = 2 ;
vt - > utf_char = ( c & 0x0f ) ;
} else if ( ( c & 0xf8 ) = = 0xf0 ) {
vt - > utf_count = 3 ;
vt - > utf_char = ( c & 0x07 ) ;
} else if ( ( c & 0xfc ) = = 0xf8 ) {
vt - > utf_count = 4 ;
vt - > utf_char = ( c & 0x03 ) ;
} else if ( ( c & 0xfe ) = = 0xfc ) {
vt - > utf_count = 5 ;
vt - > utf_char = ( c & 0x01 ) ;
} else
vt - > utf_count = 0 ;
continue ;
}
} else {
// utf8 single byte
tc = c ;
vt - > utf_count = 0 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
} else {
// never translate controls
if ( c > = 32 & & c ! = 127 & & c ! = ( 128 + 27 ) ) {
tc = translations [ vt - > cur_enc ] [ c & 0x0ff ] ;
} else {
tc = c ;
}
}
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
spiceterm_putchar ( vt , tc ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-11 09:20:40 +04:00
spiceterm_show_cursor ( vt , 1 ) ;
2013-09-12 09:17:50 +04:00
2013-08-06 12:58:17 +04:00
return len ;
}
/* fixme:
void
2013-09-11 09:20:40 +04:00
spiceterm_set_xcut_text ( char * str , int len , struct _rfbClientRec * cl )
2013-08-06 12:58:17 +04:00
{
2013-09-11 09:20:40 +04:00
spiceTerm * vt = ( spiceTerm * ) cl - > screen - > screenData ;
2013-08-06 12:58:17 +04:00
// seems str is Latin-1 encoded
if ( vt - > selection ) free ( vt - > selection ) ;
2013-09-11 15:15:53 +04:00
vt - > selection = ( gunichar2 * ) malloc ( len * sizeof ( gunichar2 ) ) ;
2013-08-06 12:58:17 +04:00
int i ;
for ( i = 0 ; i < len ; i + + ) {
vt - > selection [ i ] = str [ i ] & 0xff ;
}
vt - > selection_len = len ;
}
*/
2013-09-12 17:36:37 +04:00
2013-09-13 09:38:07 +04:00
static void
spiceterm_update_watch_mask ( spiceTerm * vt , gboolean writable )
{
g_assert ( vt ! = NULL ) ;
int mask = SPICE_WATCH_EVENT_READ ;
if ( writable ) {
mask | = SPICE_WATCH_EVENT_WRITE ;
}
vt - > screen - > core - > watch_update_mask ( vt - > screen - > mwatch , mask ) ;
}
2013-08-06 12:58:17 +04:00
static void
2013-09-12 17:36:37 +04:00
mouse_report ( spiceTerm * vt , int butt , int mrx , int mry )
2013-08-06 12:58:17 +04:00
{
2013-09-12 17:36:37 +04:00
char buf [ 8 ] ;
sprintf ( buf , " [M%c%c%c " , ( char ) ( ' ' + butt ) , ( char ) ( ' ! ' + mrx ) ,
( char ) ( ' ! ' + mry ) ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 17:36:37 +04:00
spiceterm_respond_esc ( vt , buf ) ;
2013-09-13 09:38:07 +04:00
spiceterm_update_watch_mask ( vt , TRUE ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-13 11:53:24 +04:00
static void
spiceterm_respond_unichar2 ( spiceTerm * vt , gunichar2 uc )
2013-08-06 12:58:17 +04:00
{
2013-09-13 11:53:24 +04:00
if ( vt - > utf8 ) {
gchar buf [ 10 ] ;
gint len = g_unichar_to_utf8 ( uc , buf ) ;
if ( len > 0 ) {
if ( ( vt - > ibuf_count + len ) < IBUFSIZE ) {
int i ;
for ( i = 0 ; i < len ; i + + ) {
vt - > ibuf [ vt - > ibuf_count + + ] = buf [ i ] ;
}
} else {
fprintf ( stderr , " warning: input buffer overflow \n " ) ;
}
}
2013-08-06 12:58:17 +04:00
} else {
2013-09-13 11:53:24 +04:00
if ( ( vt - > ibuf_count + 1 ) < IBUFSIZE ) {
vt - > ibuf [ vt - > ibuf_count + + ] = ( char ) uc ;
} else {
fprintf ( stderr , " warning: input buffer overflow \n " ) ;
}
2013-08-06 12:58:17 +04:00
}
}
2013-09-12 16:22:05 +04:00
static void
spiceterm_motion_event ( spiceTerm * vt , uint32_t x , uint32_t y , uint32_t buttons )
{
2013-09-13 11:53:24 +04:00
DPRINTF ( 1 , " mask=%08x x=%d y=%d " , buttons , x , y ) ;
2013-09-12 17:36:37 +04:00
static int last_mask = 0 ;
2013-09-13 11:53:24 +04:00
static int sel_start_pos = 0 ;
static int sel_end_pos = 0 ;
static int button2_released = 1 ;
2013-09-12 17:36:37 +04:00
2013-09-13 11:53:24 +04:00
int i ;
2013-09-12 17:36:37 +04:00
int cx = x / 8 ;
int cy = y / 16 ;
if ( cx < 0 ) cx = 0 ;
if ( cx > = vt - > width ) cx = vt - > width - 1 ;
if ( cy < 0 ) cy = 0 ;
if ( cy > = vt - > height ) cy = vt - > height - 1 ;
if ( vt - > report_mouse & & buttons ! = last_mask ) {
last_mask = buttons ;
if ( buttons & 2 ) {
mouse_report ( vt , 0 , cx , cy ) ;
}
if ( buttons & 4 ) {
mouse_report ( vt , 1 , cx , cy ) ;
}
if ( buttons & 8 ) {
mouse_report ( vt , 2 , cx , cy ) ;
}
if ( ! buttons ) {
mouse_report ( vt , 3 , cx , cy ) ;
}
}
2013-09-13 11:53:24 +04:00
if ( buttons & 4 ) {
if ( button2_released & & vt - > selection ) {
int i ;
for ( i = 0 ; i < vt - > selection_len ; i + + ) {
spiceterm_respond_unichar2 ( vt , vt - > selection [ i ] ) ;
}
spiceterm_update_watch_mask ( vt , TRUE ) ;
if ( vt - > y_displ ! = vt - > y_base ) {
vt - > y_displ = vt - > y_base ;
spiceterm_refresh ( vt ) ;
}
}
button2_released = 0 ;
} else {
button2_released = 1 ;
}
if ( buttons & 2 ) {
int pos = cy * vt - > width + cx ;
// code borrowed from libvncserver (VNCconsole.c)
if ( ! vt - > mark_active ) {
if ( sel_start_pos ! = sel_end_pos ) {
while ( sel_start_pos < = sel_end_pos ) {
spiceterm_toggle_marked_cell ( vt , sel_start_pos + + ) ;
}
}
vt - > mark_active = 1 ;
sel_start_pos = sel_end_pos = pos ;
spiceterm_toggle_marked_cell ( vt , pos ) ;
} else {
if ( pos ! = sel_end_pos ) {
if ( pos > sel_end_pos ) {
cx = sel_end_pos ; cy = pos ;
} else {
cx = pos ; cy = sel_end_pos ;
}
if ( cx < sel_start_pos ) {
if ( cy < sel_start_pos ) cy - - ;
} else {
cx + + ;
}
while ( cx < = cy ) {
spiceterm_toggle_marked_cell ( vt , cx ) ;
cx + + ;
}
sel_end_pos = pos ;
}
}
} else if ( vt - > mark_active ) {
vt - > mark_active = 0 ;
if ( sel_start_pos > sel_end_pos ) {
int tmp = sel_start_pos - 1 ;
sel_start_pos = sel_end_pos ;
sel_end_pos = tmp ;
}
int len = sel_end_pos - sel_start_pos + 1 ;
if ( vt - > selection ) free ( vt - > selection ) ;
vt - > selection = ( gunichar2 * ) malloc ( len * sizeof ( gunichar2 ) ) ;
vt - > selection_len = len ;
for ( i = 0 ; i < len ; i + + ) {
int pos = sel_start_pos + i ;
int x = pos % vt - > width ;
int y1 = ( ( pos / vt - > width ) + vt - > y_displ ) % vt - > total_height ;
TextCell * c = & vt - > cells [ y1 * vt - > width + x ] ;
vt - > selection [ i ] = c - > ch ;
c + + ;
}
DPRINTF ( 1 , " selection length = %d " , vt - > selection_len ) ;
// fixme: tell client we have something seletced
//rfbGotXCutText (vt->screen, sel_latin1, len);
}
2013-09-12 16:22:05 +04:00
}
2013-09-12 09:17:50 +04:00
static void
my_kbd_push_key ( SpiceKbdInstance * sin , uint8_t frag )
2013-08-06 12:58:17 +04:00
{
2013-09-11 09:20:40 +04:00
// spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, keyboard_sin);
2013-08-06 12:58:17 +04:00
2013-08-21 17:23:52 +04:00
/* we no not need this */
2013-08-21 09:43:55 +04:00
2013-08-21 17:23:52 +04:00
return ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:17:50 +04:00
static void
my_kbd_push_keyval ( SpiceKbdInstance * sin , uint32_t keySym , int flags )
2013-08-21 09:36:44 +04:00
{
2013-09-11 09:20:40 +04:00
spiceTerm * vt = SPICE_CONTAINEROF ( sin , spiceTerm , keyboard_sin ) ;
2013-08-21 14:00:42 +04:00
static int control = 0 ;
static int shift = 0 ;
char * esc = NULL ;
2013-09-13 11:53:24 +04:00
gunichar2 uc = 0 ;
2013-08-21 14:00:42 +04:00
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " flags=%d keySym=%08x " , flags , keySym ) ;
2013-09-11 14:56:28 +04:00
2013-08-21 17:23:52 +04:00
if ( flags & 1 ) {
2013-08-21 14:00:42 +04:00
if ( keySym = = GDK_KEY_Shift_L | | keySym = = GDK_KEY_Shift_R ) {
shift = 1 ;
} if ( keySym = = GDK_KEY_Control_L | | keySym = = GDK_KEY_Control_R ) {
control = 1 ;
} else if ( vt - > ibuf_count < ( IBUFSIZE - 32 ) ) {
if ( control ) {
if ( keySym > = ' a ' & & keySym < = ' z ' )
2013-08-21 17:23:52 +04:00
uc = keySym - ' a ' + 1 ;
2013-08-21 14:00:42 +04:00
else if ( keySym > = ' A ' & & keySym < = ' Z ' )
2013-08-21 17:23:52 +04:00
uc = keySym - ' A ' + 1 ;
2013-08-21 14:00:42 +04:00
else
2013-08-21 17:23:52 +04:00
uc = 0 ;
2013-08-21 14:00:42 +04:00
} else {
switch ( keySym ) {
case GDK_KEY_Escape :
2013-08-21 17:23:52 +04:00
uc = 27 ; break ;
2013-08-21 14:00:42 +04:00
case GDK_KEY_Return :
2013-08-21 17:23:52 +04:00
uc = ' \r ' ; break ;
2013-08-21 14:00:42 +04:00
case GDK_KEY_BackSpace :
2013-08-21 17:23:52 +04:00
uc = 8 ; break ;
2013-08-21 14:00:42 +04:00
case GDK_KEY_Tab :
2013-08-21 17:23:52 +04:00
uc = ' \t ' ; break ;
2013-08-21 14:00:42 +04:00
case GDK_KEY_Delete : /* kdch1 */
case GDK_KEY_KP_Delete :
esc = " [3~ " ; break ;
case GDK_KEY_Home : /* khome */
case GDK_KEY_KP_Home :
esc = " OH " ; break ;
case GDK_KEY_End :
case GDK_KEY_KP_End : /* kend */
esc = " OF " ; break ;
case GDK_KEY_Insert : /* kich1 */
case GDK_KEY_KP_Insert :
esc = " [2~ " ; break ;
case GDK_KEY_Up :
case GDK_KEY_KP_Up : /* kcuu1 */
esc = " OA " ; break ;
case GDK_KEY_Down : /* kcud1 */
case GDK_KEY_KP_Down :
esc = " OB " ; break ;
case GDK_KEY_Right :
case GDK_KEY_KP_Right : /* kcuf1 */
esc = " OC " ; break ;
case GDK_KEY_Left :
case GDK_KEY_KP_Left : /* kcub1 */
esc = " OD " ; break ;
case GDK_KEY_Page_Up :
if ( shift ) {
2013-09-11 09:20:40 +04:00
spiceterm_virtual_scroll ( vt , - vt - > height / 2 ) ;
2013-08-21 14:20:23 +04:00
goto ret ;
2013-08-21 14:00:42 +04:00
}
esc = " [5~ " ; break ;
case GDK_KEY_Page_Down :
if ( shift ) {
2013-09-11 09:20:40 +04:00
spiceterm_virtual_scroll ( vt , vt - > height / 2 ) ;
2013-08-21 14:20:23 +04:00
goto ret ;
2013-08-21 14:00:42 +04:00
}
esc = " [6~ " ; break ;
case GDK_KEY_F1 :
esc = " OP " ; break ;
case GDK_KEY_F2 :
esc = " OQ " ; break ;
case GDK_KEY_F3 :
esc = " OR " ; break ;
case GDK_KEY_F4 :
esc = " OS " ; break ;
case GDK_KEY_F5 :
esc = " [15~ " ; break ;
case GDK_KEY_F6 :
esc = " [17~ " ; break ;
case GDK_KEY_F7 :
esc = " [18~ " ; break ;
case GDK_KEY_F8 :
esc = " [19~ " ; break ;
case GDK_KEY_F9 :
esc = " [20~ " ; break ;
case GDK_KEY_F10 :
esc = " [21~ " ; break ;
case GDK_KEY_F11 :
esc = " [23~ " ; break ;
case GDK_KEY_F12 :
esc = " [24~ " ; break ;
default :
2013-08-21 17:23:52 +04:00
if ( keySym < 0x100 ) {
uc = keySym ;
}
2013-08-21 14:00:42 +04:00
break ;
}
}
2013-08-21 09:36:44 +04:00
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " escape=%s unicode=%08x \n " , esc , uc ) ;
2013-08-21 09:36:44 +04:00
2013-08-21 14:00:42 +04:00
if ( vt - > y_displ ! = vt - > y_base ) {
vt - > y_displ = vt - > y_base ;
2013-09-11 09:20:40 +04:00
spiceterm_refresh ( vt ) ;
2013-08-21 14:00:42 +04:00
}
2013-09-12 09:16:03 +04:00
2013-08-21 14:00:42 +04:00
if ( esc ) {
2013-09-11 09:20:40 +04:00
spiceterm_respond_esc ( vt , esc ) ;
2013-08-21 17:23:52 +04:00
} else if ( uc > 0 ) {
2013-09-13 11:53:24 +04:00
spiceterm_respond_unichar2 ( vt , uc ) ;
2013-08-21 09:36:44 +04:00
}
2013-08-21 14:20:23 +04:00
}
2013-08-21 14:00:42 +04:00
}
2013-08-21 17:23:52 +04:00
ret :
2013-08-21 14:00:42 +04:00
if ( flags & 2 ) { // UP
if ( keySym = = GDK_KEY_Shift_L | | keySym = = GDK_KEY_Shift_R ) {
shift = 0 ;
} else if ( keySym = = GDK_KEY_Control_L | | keySym = = GDK_KEY_Control_R ) {
control = 0 ;
2013-08-21 09:36:44 +04:00
}
}
2013-08-21 14:20:23 +04:00
2013-09-13 09:38:07 +04:00
spiceterm_update_watch_mask ( vt , TRUE ) ;
2013-08-21 09:36:44 +04:00
}
2013-09-12 09:17:50 +04:00
static uint8_t
my_kbd_get_leds ( SpiceKbdInstance * sin )
2013-08-06 12:58:17 +04:00
{
return 0 ;
}
static SpiceKbdInterface my_keyboard_sif = {
2013-09-12 16:22:05 +04:00
. base . type = SPICE_INTERFACE_KEYBOARD ,
2013-08-06 12:58:17 +04:00
. base . description = " spiceterm keyboard device " ,
. base . major_version = SPICE_INTERFACE_KEYBOARD_MAJOR ,
. base . minor_version = SPICE_INTERFACE_KEYBOARD_MINOR ,
2013-08-21 14:00:42 +04:00
. push_keyval = my_kbd_push_keyval ,
2013-08-06 12:58:17 +04:00
. push_scan_freg = my_kbd_push_key ,
. get_leds = my_kbd_get_leds ,
} ;
2013-09-12 16:22:05 +04:00
/* vdagent interface - to get mouse/clipboarde support */
static int
vmc_write ( SpiceCharDeviceInstance * sin , const uint8_t * buf , int len )
{
spiceTerm * vt = SPICE_CONTAINEROF ( sin , spiceTerm , vdagent_sin ) ;
VDIChunkHeader * hdr = ( VDIChunkHeader * ) buf ;
VDAgentMessage * msg = ( VDAgentMessage * ) & hdr [ 1 ] ;
//g_assert(hdr->port == VDP_SERVER_PORT);
g_assert ( msg - > protocol = = VD_AGENT_PROTOCOL ) ;
DPRINTF ( 1 , " %d %d %d %d " , len , hdr - > port , msg - > protocol , msg - > type ) ;
if ( msg - > type = = VD_AGENT_MOUSE_STATE ) {
VDAgentMouseState * info = ( VDAgentMouseState * ) & msg [ 1 ] ;
spiceterm_motion_event ( vt , info - > x , info - > y , info - > buttons ) ;
} else if ( msg - > type = = VD_AGENT_ANNOUNCE_CAPABILITIES ) {
/* ignore for now */
} else if ( msg - > type = = VD_AGENT_MONITORS_CONFIG ) {
/* ignore for now */
} else {
DPRINTF ( 0 , " got uknown vdagent message type %d \n " , msg - > type ) ;
}
return len ;
}
static int
vmc_read ( SpiceCharDeviceInstance * sin , uint8_t * buf , int len )
{
2013-09-12 17:36:37 +04:00
DPRINTF ( 1 , " %d " , len ) ;
2013-09-12 16:22:05 +04:00
return 0 ;
}
static void
vmc_state ( SpiceCharDeviceInstance * sin , int connected )
{
2013-09-12 17:36:37 +04:00
/* IGNORE */
2013-09-12 16:22:05 +04:00
}
static SpiceCharDeviceInterface my_vdagent_sif = {
. base . type = SPICE_INTERFACE_CHAR_DEVICE ,
. base . description = " spice virtual channel char device " ,
. base . major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR ,
. base . minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR ,
. state = vmc_state ,
. write = vmc_write ,
. read = vmc_read ,
} ;
2013-09-12 14:23:05 +04:00
static spiceTerm *
create_spiceterm ( int argc , char * * argv , int maxx , int maxy , guint timeout )
2013-08-06 12:58:17 +04:00
{
2013-09-12 09:16:03 +04:00
int i ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
SpiceScreen * spice_screen ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
SpiceCoreInterface * core = basic_event_loop_init ( ) ;
2013-09-12 14:23:05 +04:00
spice_screen = spice_screen_new ( core , timeout ) ;
2013-09-12 09:16:03 +04:00
//spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF);
2013-08-21 09:43:55 +04:00
2013-09-12 09:16:03 +04:00
spiceTerm * vt = ( spiceTerm * ) calloc ( sizeof ( spiceTerm ) , 1 ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > keyboard_sin . base . sif = & my_keyboard_sif . base ;
spice_server_add_interface ( spice_screen - > server , & vt - > keyboard_sin . base ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 16:22:05 +04:00
vt - > vdagent_sin . base . sif = & my_vdagent_sif . base ;
vt - > vdagent_sin . subtype = " vdagent " ;
spice_server_add_interface ( spice_screen - > server , & vt - > vdagent_sin . base ) ;
2013-09-12 09:16:03 +04:00
// screen->setXCutText = spiceterm_set_xcut_text;
// screen->ptrAddEvent = spiceterm_pointer_event;
// screen->newClientHook = new_client;
// screen->desktopName = "SPICE Command Terminal";
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > maxx = spice_screen - > width ;
vt - > maxy = spice_screen - > height ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > width = vt - > maxx / 8 ;
vt - > height = vt - > maxy / 16 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > total_height = vt - > height * 20 ;
vt - > scroll_height = 0 ;
vt - > y_base = 0 ;
vt - > y_displ = 0 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > region_top = 0 ;
vt - > region_bottom = vt - > height ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > g0enc = LAT1_MAP ;
vt - > g1enc = GRAF_MAP ;
vt - > cur_enc = vt - > g0enc ;
vt - > charset = 0 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
/* default text attributes */
vt - > default_attrib . bold = 0 ;
vt - > default_attrib . uline = 0 ;
vt - > default_attrib . blink = 0 ;
vt - > default_attrib . invers = 0 ;
vt - > default_attrib . unvisible = 0 ;
vt - > default_attrib . fgcol = 7 ;
vt - > default_attrib . bgcol = 0 ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > cur_attrib = vt - > default_attrib ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > cells = ( TextCell * ) calloc ( sizeof ( TextCell ) , vt - > width * vt - > total_height ) ;
2013-09-12 09:17:50 +04:00
2013-09-12 09:16:03 +04:00
for ( i = 0 ; i < vt - > width * vt - > total_height ; i + + ) {
vt - > cells [ i ] . ch = ' ' ;
vt - > cells [ i ] . attrib = vt - > default_attrib ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > altcells = ( TextCell * ) calloc ( sizeof ( TextCell ) , vt - > width * vt - > height ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
vt - > screen = spice_screen ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
return vt ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 12:54:21 +04:00
static gboolean
master_error_callback ( GIOChannel * channel , GIOCondition condition ,
gpointer data )
{
//spiceTerm *vt = (spiceTerm *)data;
DPRINTF ( 1 , " condition %d " , condition ) ;
exit ( 0 ) ;
return FALSE ;
}
2013-09-12 09:17:50 +04:00
static void
master_watch ( int master , int event , void * opaque )
2013-08-06 12:58:17 +04:00
{
2013-09-11 09:20:40 +04:00
spiceTerm * vt = ( spiceTerm * ) opaque ;
2013-09-13 09:52:54 +04:00
int c ;
2013-08-06 12:58:17 +04:00
// fixme: if (!vt->mark_active) {
if ( event = = SPICE_WATCH_EVENT_READ ) {
char buffer [ 1024 ] ;
while ( ( c = read ( master , buffer , 1024 ) ) = = - 1 ) {
if ( errno ! = EAGAIN ) break ;
}
if ( c = = - 1 ) {
2013-09-13 09:52:54 +04:00
perror ( " master pipe read error " ) ; // fixme
2013-08-06 12:58:17 +04:00
}
2013-09-11 09:20:40 +04:00
spiceterm_puts ( vt , buffer , c ) ;
2013-08-06 12:58:17 +04:00
} else {
if ( vt - > ibuf_count > 0 ) {
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " write input %x %d " , vt - > ibuf [ 0 ] , vt - > ibuf_count ) ;
2013-09-13 09:52:54 +04:00
if ( ( c = write ( master , vt - > ibuf , vt - > ibuf_count ) ) > = 0 ) {
if ( c = = vt - > ibuf_count ) {
vt - > ibuf_count = 0 ;
} else if ( c > 0 ) {
// not all data written
memmove ( vt - > ibuf , vt - > ibuf + c , vt - > ibuf_count - c ) ;
vt - > ibuf_count - = c ;
} else {
// nothing written -ignore and try later
}
} else {
perror ( " master pipe write error " ) ;
}
}
if ( vt - > ibuf_count = = 0 ) {
spiceterm_update_watch_mask ( vt , FALSE ) ;
2013-08-06 12:58:17 +04:00
}
}
}
int
main ( int argc , char * * argv )
{
2013-09-12 09:16:03 +04:00
int i ;
char * * cmdargv = NULL ;
char * command = " /bin/bash " ; // execute normal shell as default
int pid ;
int master ;
char ptyname [ 1024 ] ;
struct winsize dimensions ;
g_thread_init ( NULL ) ;
for ( i = 1 ; i < argc ; i + + ) {
if ( ! strcmp ( argv [ i ] , " -c " ) ) {
command = argv [ i + 1 ] ;
cmdargv = & argv [ i + 1 ] ;
argc = i ;
argv [ i ] = NULL ;
break ;
}
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
if ( 0 ) print_usage ( NULL ) ; // fixme:
2013-09-10 15:05:05 +04:00
2013-09-12 14:23:05 +04:00
spiceTerm * vt = create_spiceterm ( argc , argv , 745 , 400 , 10 ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
setlocale ( LC_ALL , " " ) ; // set from environment
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
char * ctype = setlocale ( LC_CTYPE , NULL ) ; // query LC_CTYPE
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
// fixme: ist there a standard way to detect utf8 mode ?
if ( strcasestr ( ctype , " .utf-8 " ) | | strcasestr ( ctype , " .utf8 " ) ) {
vt - > utf8 = 1 ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
dimensions . ws_col = vt - > width ;
dimensions . ws_row = vt - > height ;
2013-08-06 12:58:17 +04:00
2013-09-12 17:36:37 +04:00
setenv ( " TERM " , TERM , 1 ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 11:26:44 +04:00
DPRINTF ( 1 , " execute %s " , command ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
pid = forkpty ( & master , ptyname , NULL , & dimensions ) ;
if ( ! pid ) {
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
// install default signal handlers
signal ( SIGQUIT , SIG_DFL ) ;
signal ( SIGTERM , SIG_DFL ) ;
signal ( SIGINT , SIG_DFL ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( cmdargv ) {
execvp ( command , cmdargv ) ;
} else {
execlp ( command , command , NULL ) ;
}
perror ( " Error: exec failed \n " ) ;
exit ( - 1 ) ; // should not be reached
} else if ( pid = = - 1 ) {
perror ( " Error: fork failed \n " ) ;
exit ( - 1 ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 12:54:21 +04:00
/* watch for errors - we need to use glib directly because spice
* does not have SPICE_WATCH_EVENT for this */
GIOChannel * channel = g_io_channel_unix_new ( master ) ;
g_io_channel_set_flags ( channel , G_IO_FLAG_NONBLOCK , NULL ) ;
g_io_channel_set_encoding ( channel , NULL , NULL ) ;
g_io_add_watch ( channel , G_IO_ERR | G_IO_HUP , master_error_callback , vt ) ;
2013-09-12 09:16:03 +04:00
vt - > screen - > mwatch = vt - > screen - > core - > watch_add (
master , SPICE_WATCH_EVENT_READ /* |SPICE_WATCH_EVENT_WRITE */ ,
master_watch , vt ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
basic_event_loop_mainloop ( ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
kill ( pid , 9 ) ;
int status ;
waitpid ( pid , & status , 0 ) ;
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
exit ( 0 ) ;
2013-08-06 12:58:17 +04:00
}