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>
2013-10-25 15:31:16 +04:00
# include <getopt.h>
2013-08-06 12:58:17 +04:00
# 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-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
/* 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-13 12:56:03 +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-13 12:56:03 +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 ] ;
2013-09-13 12:56:03 +04:00
draw_char_at ( vt , x , y2 , c - > ch , c - > attrib ) ;
2013-09-12 09:16:03 +04:00
}
2013-08-06 12:58:17 +04:00
}
static void
2013-09-13 12:56:03 +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 ;
2013-09-13 12:56:03 +04:00
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
2013-09-12 09:16:03 +04:00
}
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 ; }
2013-09-13 12:47:02 +04:00
int y1 = ( vt - > y_displ + y ) % vt - > total_height ;
TextCell * c = & vt - > cells [ y1 * vt - > width + x ] ;
c - > attrib . selected = c - > attrib . selected ? 0 : 1 ;
if ( y < vt - > height ) {
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
2013-09-13 11:53:24 +04:00
}
}
2013-08-06 12:58:17 +04:00
static void
2013-09-13 12:56:03 +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 */
2013-09-13 12:56:03 +04:00
draw_char_at ( vt , x , y , c - > ch , attrib ) ;
2013-09-12 09:16:03 +04:00
} else {
2013-09-13 12:56:03 +04:00
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
2013-09-12 09:16:03 +04:00
}
2013-08-06 12:58:17 +04:00
}
}
2013-10-17 10:44:52 +04:00
void
2013-09-13 12:47:02 +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 + + ) {
2013-09-13 12:47:02 +04:00
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
2013-09-12 09:16:03 +04:00
c + + ;
}
if ( + + y1 = = vt - > total_height )
y1 = 0 ;
2013-08-06 12:58:17 +04:00
}
2013-09-13 12:47:02 +04:00
spiceterm_show_cursor ( vt , 1 ) ;
}
2013-10-09 13:32:12 +04:00
static void
spiceterm_clear_screen ( spiceTerm * vt )
{
int x , y ;
for ( y = 0 ; y < = vt - > height ; y + + ) {
int y1 = ( vt - > y_base + y ) % vt - > total_height ;
TextCell * c = & vt - > cells [ y1 * vt - > width ] ;
for ( x = 0 ; x < vt - > width ; x + + ) {
c - > ch = ' ' ;
c - > attrib = vt - > default_attrib ;
c - > attrib . fgcol = vt - > cur_attrib . fgcol ;
c - > attrib . bgcol = vt - > cur_attrib . bgcol ;
c + + ;
}
}
spice_screen_clear ( vt - > screen , 0 , 0 , vt - > screen - > primary_width ,
vt - > screen - > primary_height ) ;
}
2013-09-13 12:47:02 +04:00
void
spiceterm_unselect_all ( spiceTerm * vt )
{
2013-10-09 11:30:56 +04:00
int x , y , y1 ;
2013-09-13 12:47:02 +04:00
2013-10-09 11:30:56 +04:00
y1 = vt - > y_displ ;
for ( y = 0 ; y < vt - > total_height ; y + + ) {
TextCell * c = vt - > cells + y1 * vt - > width ;
for ( x = 0 ; x < vt - > width ; x + + ) {
if ( c - > attrib . selected ) {
c - > attrib . selected = 0 ;
if ( y < vt - > height ) {
draw_char_at ( vt , x , y , c - > ch , c - > attrib ) ;
}
}
c + + ;
2013-09-13 12:47:02 +04:00
}
2013-10-09 11:30:56 +04:00
if ( + + y1 = = vt - > total_height )
y1 = 0 ;
2013-09-13 12:47:02 +04:00
}
2013-08-06 12:58:17 +04:00
}
static void
2013-09-13 12:56:03 +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-09-13 12:56:03 +04:00
memmove ( vt - > cells + dst , vt - > cells + src , vt - > width * sizeof ( TextCell ) ) ;
2013-08-21 16:30:16 +04:00
}
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-13 12:56:03 +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-09-13 12:56:03 +04:00
memmove ( vt - > cells + dst , vt - > cells + src , vt - > width * sizeof ( TextCell ) ) ;
2013-08-21 16:30:16 +04:00
}
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
}
}
2013-10-17 10:44:52 +04:00
void
2013-09-13 12:56:03 +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-13 12:56:03 +04:00
spiceterm_refresh ( vt ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-12 09:16:03 +04:00
2013-10-17 10:44:52 +04:00
void
2013-09-13 12:56:03 +04:00
spiceterm_respond_esc ( spiceTerm * vt , const char * esc )
2013-08-06 12:58:17 +04:00
{
2013-09-13 12:56:03 +04:00
int len = strlen ( esc ) ;
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
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-10-17 10:44:52 +04:00
} else {
fprintf ( stderr , " input buffer oferflow \n " ) ;
return ;
}
}
void
spiceterm_respond_data ( spiceTerm * vt , int len , uint8_t * data )
{
int i ;
if ( vt - > ibuf_count < ( IBUFSIZE - len ) ) {
for ( i = 0 ; i < len ; i + + ) {
vt - > ibuf [ vt - > ibuf_count + + ] = data [ i ] ;
}
} else {
fprintf ( stderr , " input buffer oferflow \n " ) ;
return ;
2013-08-06 12:58:17 +04:00
}
}
static void
2013-09-13 12:56:03 +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 ) {
2013-09-13 12:56:03 +04:00
spiceterm_scroll_up ( vt , vt - > region_top , vt - > region_bottom , 1 , 1 ) ;
2013-09-12 09:16:03 +04:00
return ;
}
2013-08-06 12:58:17 +04:00
2013-09-12 09:16:03 +04:00
if ( vt - > y_displ = = vt - > y_base ) {
2013-09-13 12:56:03 +04:00
spiceterm_scroll_up ( vt , vt - > region_top , vt - > region_bottom , 1 , 0 ) ;
2013-09-12 09:16:03 +04:00
}
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-13 12:56:03 +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-13 12:56:03 +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-13 12:56:03 +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-13 12:56:03 +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-13 12:56:03 +04:00
spiceterm_save_cursor ( vt ) ;
2013-09-12 09:16:03 +04:00
/* 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 + + ) {
2013-09-17 15:47:33 +04:00
// spiceterm_clear_xy(vt, x, y);
2013-09-12 09:16:03 +04:00
}
}
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-13 12:56:03 +04:00
spiceterm_restore_cursor ( vt ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-13 12:56:03 +04:00
spiceterm_refresh ( vt ) ;
2013-08-06 12:58:17 +04:00
}
static void
2013-09-13 12:56:03 +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-13 12:56:03 +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-13 12:56:03 +04:00
static void
2013-09-12 11:26:44 +04:00
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-13 12:56:03 +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 ' :
2013-09-13 12:56:03 +04:00
spiceterm_save_cursor ( vt ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' 8 ' :
2013-09-13 12:56:03 +04:00
spiceterm_restore_cursor ( vt ) ;
2013-09-12 09:16:03 +04:00
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 )
2013-09-13 12:56:03 +04:00
spiceterm_scroll_down ( vt , vt - > region_top , vt - > region_bottom , 1 ) ;
2013-09-12 09:16:03 +04:00
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
}
2013-09-13 12:56:03 +04:00
spiceterm_csi_m ( vt ) ;
2013-09-12 09:16:03 +04:00
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 */
2013-09-13 12:56:03 +04:00
spiceterm_gotoxy ( vt , vt - > esc_buf [ 0 ] - 1 , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' d ' :
/* move cursor to row */
2013-09-13 12:56:03 +04:00
spiceterm_gotoxy ( vt , vt - > cx , vt - > esc_buf [ 0 ] - 1 ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' f ' :
case ' H ' :
/* move cursor to row, column */
2013-09-13 12:56:03 +04:00
spiceterm_gotoxy ( vt , vt - > esc_buf [ 1 ] - 1 , vt - > esc_buf [ 0 ] - 1 ) ;
2013-09-12 09:16:03 +04:00
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 ;
}
2013-09-13 12:56:03 +04:00
spiceterm_clear_xy ( vt , x , y ) ;
2013-09-12 09:16:03 +04:00
}
}
break ;
case 2 :
/* clear entire screen */
2013-10-09 13:32:12 +04:00
spiceterm_clear_screen ( vt ) ;
2013-09-12 09:16:03 +04:00
break ;
}
break ;
case ' K ' :
switch ( vt - > esc_buf [ 0 ] ) {
case 0 :
/* clear to eol */
for ( x = vt - > cx ; x < vt - > width ; x + + ) {
2013-09-13 12:56:03 +04:00
spiceterm_clear_xy ( vt , x , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
}
break ;
case 1 :
/* clear from beginning of line */
for ( x = 0 ; x < = vt - > cx ; x + + ) {
2013-09-13 12:56:03 +04:00
spiceterm_clear_xy ( vt , x , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
}
break ;
case 2 :
/* clear entire line */
for ( x = 0 ; x < vt - > width ; x + + ) {
2013-09-13 12:56:03 +04:00
spiceterm_clear_xy ( vt , x , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
}
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 ;
2013-09-13 12:56:03 +04:00
spiceterm_scroll_down ( vt , vt - > cy , vt - > region_bottom , c ) ;
2013-09-12 09:16:03 +04:00
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 ;
2013-09-13 12:56:03 +04:00
spiceterm_scroll_up ( vt , vt - > cy , vt - > region_bottom , c , 1 ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' T ' :
/* scroll down */
c = vt - > esc_buf [ 0 ] ;
if ( ! c ) c = 1 ;
2013-09-13 12:56:03 +04:00
spiceterm_scroll_down ( vt , vt - > region_top , vt - > region_bottom , c ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' S ' :
/* scroll up */
c = vt - > esc_buf [ 0 ] ;
if ( ! c ) c = 1 ;
2013-09-13 12:56:03 +04:00
spiceterm_scroll_up ( vt , vt - > region_top , vt - > region_bottom , c , 1 ) ;
2013-09-12 09:16:03 +04:00
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 ;
2013-09-13 12:56:03 +04:00
spiceterm_update_xy ( vt , x + c , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
src - > ch = ' ' ;
src - > attrib = vt - > default_attrib ;
2013-09-13 12:56:03 +04:00
spiceterm_update_xy ( vt , x , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
}
break ;
case ' s ' :
/* save cursor position */
2013-09-13 12:56:03 +04:00
spiceterm_save_cursor ( vt ) ;
2013-09-12 09:16:03 +04:00
break ;
case ' u ' :
/* restore cursor position */
2013-09-13 12:56:03 +04:00
spiceterm_restore_cursor ( vt ) ;
2013-09-12 09:16:03 +04:00
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 + + ) {
2013-09-13 12:56:03 +04:00
spiceterm_clear_xy ( vt , vt - > cx + i , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
}
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 ;
2013-09-13 12:56:03 +04:00
spiceterm_update_xy ( vt , x , vt - > cy ) ;
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 ;
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-13 12:56: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 ;
2013-09-13 12:56:03 +04:00
spiceterm_put_lf ( vt ) ;
2013-09-12 09:16:03 +04:00
} else {
vt - > cx = vt - > cx + ( 8 - ( vt - > cx % 8 ) ) ;
}
break ;
case 10 : /* LF,*/
case 11 : /* VT */
case 12 : /* FF */
2013-09-13 12:56:03 +04:00
spiceterm_put_lf ( vt ) ;
2013-09-12 09:16:03 +04:00
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 ;
2013-09-13 12:56:03 +04:00
spiceterm_put_lf ( vt ) ;
2013-09-12 09:16:03 +04:00
}
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 ;
2013-09-13 12:56:03 +04:00
spiceterm_update_xy ( vt , vt - > cx , vt - > cy ) ;
2013-09-12 09:16:03 +04:00
vt - > cx + + ;
break ;
}
break ;
2013-08-06 12:58:17 +04:00
}
}
static int
2013-09-13 12:56:03 +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-13 12:56:03 +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-13 12:56:03 +04:00
spiceterm_putchar ( vt , tc ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-13 12:56:03 +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 ;
}
void
2013-09-13 09:38:07 +04:00
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 ] ;
2013-09-13 12:56:03 +04:00
sprintf ( buf , " [M%c%c%c " , ( char ) ( ' ' + butt ) , ( char ) ( ' ! ' + mrx ) ,
2013-09-12 17:36:37 +04:00
( 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 ) {
2013-10-17 10:44:52 +04:00
spiceterm_respond_data ( vt , len , ( uint8_t * ) buf ) ;
2013-10-16 14:19:00 +04:00
}
} else {
2013-10-17 10:44:52 +04:00
uint8_t buf [ 1 ] = { ( uint8_t ) uc } ;
spiceterm_respond_data ( vt , 1 , buf ) ;
2013-10-16 14:19:00 +04:00
}
2013-10-10 11:10:50 +04:00
}
2013-10-17 10:44:52 +04:00
void
2013-10-08 17:08:04 +04:00
spiceterm_clear_selection ( spiceTerm * vt )
{
DPRINTF ( 1 , " mark_active = %d " , vt - > mark_active ) ;
vt - > mark_active = 0 ;
if ( vt - > selection ) free ( vt - > selection ) ;
vt - > selection = NULL ;
spiceterm_unselect_all ( vt ) ;
}
2013-10-17 10:44:52 +04:00
void
2013-09-16 14:23:49 +04:00
spiceterm_motion_event ( spiceTerm * vt , uint32_t x , uint32_t y , uint32_t buttons )
{
DPRINTF ( 1 , " mask=%08x x=%d y=%d " , buttons , x , y ) ;
static int last_mask = 0 ;
static int sel_start_pos = 0 ;
static int sel_end_pos = 0 ;
static int button2_released = 1 ;
int i ;
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 ) ;
}
}
if ( buttons & 4 ) {
if ( button2_released ) {
2013-10-17 10:44:52 +04:00
if ( vdagent_owns_clipboard ( vt ) ) {
2013-09-16 14:23:49 +04:00
if ( 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 ) ;
}
}
} else {
2013-10-17 10:44:52 +04:00
vdagent_request_clipboard ( vt ) ;
2013-09-16 14:23:49 +04:00
}
}
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 ) {
spiceterm_unselect_all ( vt ) ;
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 ) ;
2013-10-17 10:44:52 +04:00
vdagent_grab_clipboard ( vt ) ;
2013-09-13 16:18:46 +04:00
}
2013-09-12 16:22:05 +04:00
}
2013-10-17 10:44:52 +04:00
void
2013-09-17 14:57:23 +04:00
init_spiceterm ( spiceTerm * vt , uint32_t width , uint32_t height )
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-17 14:57:23 +04:00
g_assert ( vt ! = NULL ) ;
g_assert ( vt - > screen ! = NULL ) ;
2013-08-06 12:58:17 +04:00
2013-09-17 14:57:23 +04:00
vt - > width = width / 8 ;
vt - > height = height / 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-17 14:57:23 +04:00
if ( vt - > cells ) {
vt - > cx = 0 ;
vt - > cy = 0 ;
vt - > cx_saved = 0 ;
vt - > cy_saved = 0 ;
g_free ( vt - > cells ) ;
}
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-09-17 14:57:23 +04:00
if ( vt - > altcells ) {
g_free ( vt - > altcells ) ;
}
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-09-17 14:57:23 +04:00
}
2013-10-17 10:44:52 +04:00
void
2013-09-17 14:57:23 +04:00
spiceterm_resize ( spiceTerm * vt , uint32_t width , uint32_t height )
{
2013-10-08 14:14:10 +04:00
width = ( width / 8 ) * 8 ;
height = ( height / 16 ) * 16 ;
2013-09-17 14:57:23 +04:00
if ( vt - > screen - > width = = width & & vt - > screen - > height = = height ) {
return ;
}
2013-10-08 14:14:10 +04:00
DPRINTF ( 0 , " width=%u height=%u " , width , height ) ;
2013-09-17 14:57:23 +04:00
spice_screen_resize ( vt - > screen , width , height ) ;
init_spiceterm ( vt , width , height ) ;
struct winsize dimensions ;
dimensions . ws_col = vt - > width ;
dimensions . ws_row = vt - > height ;
ioctl ( vt - > pty , TIOCSWINSZ , & dimensions ) ;
}
2013-09-13 12:56:03 +04:00
static gboolean
master_error_callback ( GIOChannel * channel , GIOCondition condition ,
2013-09-12 12:54:21 +04:00
gpointer data )
{
//spiceTerm *vt = (spiceTerm *)data;
DPRINTF ( 1 , " condition %d " , condition ) ;
exit ( 0 ) ;
return FALSE ;
}
2013-09-13 12:56:03 +04:00
static void
2013-09-12 09:17:50 +04:00
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 ) {
2013-09-13 12:56:03 +04:00
vt - > ibuf_count = 0 ;
2013-09-13 09:52:54 +04:00
} else if ( c > 0 ) {
// not all data written
memmove ( vt - > ibuf , vt - > ibuf + c , vt - > ibuf_count - c ) ;
2013-09-13 12:56:03 +04:00
vt - > ibuf_count - = c ;
2013-09-13 09:52:54 +04:00
} 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
}
}
}
2013-10-25 15:31:16 +04:00
static void
spiceterm_print_usage ( const char * msg )
{
if ( msg ) {
fprintf ( stderr , " ERROR: %s \n " , msg ) ;
}
fprintf ( stderr , " USAGE: spiceterm [OPTIONS] [-- command [args]] \n " ) ;
fprintf ( stderr , " --timeout <seconds> Wait this time before aborting (default is 10 seconds) \n " ) ;
fprintf ( stderr , " --authpath <path> Authentication path (PVE AUTH) \n " ) ;
fprintf ( stderr , " --permission <perm> Required permissions (PVE AUTH) \n " ) ;
fprintf ( stderr , " --port <port> Bind to port <port> \n " ) ;
fprintf ( stderr , " --addr <addr> Bind to address <addr> \n " ) ;
fprintf ( stderr , " --sasl Enable SASL based authentication \n " ) ;
fprintf ( stderr , " --noauth Disable authentication \n " ) ;
2013-10-29 12:39:30 +04:00
fprintf ( stderr , " --keymap Spefify keymap (uses kvm keymap files) \n " ) ;
2013-10-25 15:31:16 +04:00
}
2013-08-06 12:58:17 +04:00
int
main ( int argc , char * * argv )
{
2013-10-25 15:31:16 +04:00
int c ;
2013-09-12 09:16:03 +04:00
char * * cmdargv = NULL ;
char * command = " /bin/bash " ; // execute normal shell as default
int pid ;
int master ;
char ptyname [ 1024 ] ;
struct winsize dimensions ;
2013-10-25 15:31:16 +04:00
SpiceTermOptions opts = {
. timeout = 10 ,
. port = 5900 ,
. addr = NULL ,
. noauth = FALSE ,
. sasl = FALSE ,
} ;
2013-09-12 09:16:03 +04:00
g_thread_init ( NULL ) ;
2013-10-25 15:31:16 +04:00
static struct option long_options [ ] = {
{ " timeout " , required_argument , 0 , ' t ' } ,
{ " authpath " , required_argument , 0 , ' A ' } ,
{ " permissions " , required_argument , 0 , ' P ' } ,
{ " port " , required_argument , 0 , ' p ' } ,
{ " addr " , required_argument , 0 , ' a ' } ,
2013-10-29 12:39:30 +04:00
{ " keymap " , required_argument , 0 , ' k ' } ,
2013-10-25 15:31:16 +04:00
{ " noauth " , no_argument , 0 , ' n ' } ,
{ " sasl " , no_argument , 0 , ' s ' } ,
{ NULL , 0 , 0 , 0 } ,
} ;
2013-10-29 12:39:30 +04:00
while ( ( c = getopt_long ( argc , argv , " nkst:a:p:P: " , long_options , NULL ) ) ! = - 1 ) {
2013-10-25 15:31:16 +04:00
switch ( c ) {
case ' n ' :
opts . noauth = TRUE ;
break ;
case ' s ' :
opts . sasl = TRUE ;
break ;
2013-10-29 12:39:30 +04:00
case ' k ' :
opts . keymap = optarg ;
break ;
2013-10-25 15:31:16 +04:00
case ' A ' :
pve_auth_set_path ( optarg ) ;
break ;
case ' P ' :
pve_auth_set_permissions ( optarg ) ;
break ;
case ' p ' :
opts . port = atoi ( optarg ) ;
break ;
case ' a ' :
opts . addr = optarg ;
break ;
case ' t ' :
opts . timeout = atoi ( optarg ) ;
2013-09-12 09:16:03 +04:00
break ;
2013-10-25 15:31:16 +04:00
case ' ? ' :
spiceterm_print_usage ( NULL ) ;
exit ( - 1 ) ;
break ;
default :
spiceterm_print_usage ( " getopt returned unknown character code " ) ;
exit ( - 1 ) ;
2013-09-12 09:16:03 +04:00
}
2013-08-06 12:58:17 +04:00
}
2013-10-25 15:31:16 +04:00
if ( optind < argc ) {
command = argv [ optind + 1 ] ;
cmdargv = & argv [ optind + 1 ] ;
}
spiceTerm * vt = spiceterm_create ( 744 , 400 , & opts ) ;
2013-10-29 14:56:07 +04:00
if ( ! vt )
exit ( - 1 ) ;
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-17 14:57:23 +04:00
vt - > pty = master ;
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-13 12:56:03 +04:00
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
}