2013-09-11 14:08:08 +04:00
/*
Copyright ( C ) 2013 Proxmox Server Solutions GmbH
Copyright : spiceterm is under GNU GPL , the GNU General Public License .
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.
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 .
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 .
Author : Dietmar Maurer < dietmar @ proxmox . com >
Note : qlx drawing code is copied from spice - server test code .
*/
2013-08-05 11:26:20 +04:00
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include <stdio.h>
# include <unistd.h>
# include <signal.h>
# include <wait.h>
# include <sys/select.h>
# include <sys/types.h>
# include <getopt.h>
# include <spice.h>
2013-08-05 14:57:43 +04:00
# include <spice/enums.h>
2013-08-05 11:26:20 +04:00
# include <spice/macros.h>
# include <spice/qxl_dev.h>
2013-09-11 09:44:47 +04:00
# include "glyphs.h"
# include "spiceterm.h"
2013-08-05 11:26:20 +04:00
2013-09-11 14:56:28 +04:00
static int debug = 0 ;
# define DPRINTF(x, format, ...) { \
if ( x < = debug ) { \
printf ( " %s: " format " \n " , __FUNCTION__ , # # __VA_ARGS__ ) ; \
} \
}
2013-08-05 11:26:20 +04:00
# define MEM_SLOT_GROUP_ID 0
# define NOTIFY_DISPLAY_BATCH (SINGLE_PART / 2)
# define NOTIFY_CURSOR_BATCH 10
2013-08-21 10:14:37 +04:00
/* these colours are from linux kernel drivers/char/vt.c */
/* the default colour table, for VGA+ colour systems */
int default_red [ ] = { 0x00 , 0xaa , 0x00 , 0xaa , 0x00 , 0xaa , 0x00 , 0xaa ,
0x55 , 0xff , 0x55 , 0xff , 0x55 , 0xff , 0x55 , 0xff } ;
int default_grn [ ] = { 0x00 , 0x00 , 0xaa , 0x55 , 0x00 , 0x00 , 0xaa , 0xaa ,
0x55 , 0x55 , 0xff , 0xff , 0x55 , 0x55 , 0xff , 0xff } ;
int default_blu [ ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0xaa , 0xaa , 0xaa , 0xaa ,
0x55 , 0x55 , 0x55 , 0x55 , 0xff , 0xff , 0xff , 0xff } ;
2013-08-05 11:26:20 +04:00
/* Parts cribbed from spice-display.h/.c/qxl.c */
typedef struct SimpleSpiceUpdate {
QXLCommandExt ext ; // first
QXLDrawable drawable ;
QXLImage image ;
uint8_t * bitmap ;
} SimpleSpiceUpdate ;
2013-09-11 13:57:01 +04:00
static void
spice_screen_destroy_update ( SimpleSpiceUpdate * update )
2013-08-05 11:26:20 +04:00
{
if ( ! update ) {
return ;
}
if ( update - > drawable . clip . type ! = SPICE_CLIP_TYPE_NONE ) {
uint8_t * ptr = ( uint8_t * ) update - > drawable . clip . data ;
free ( ptr ) ;
}
2013-08-06 10:32:59 +04:00
g_free ( update - > bitmap ) ;
g_free ( update ) ;
2013-08-05 11:26:20 +04:00
}
# define DEFAULT_WIDTH 640
# define DEFAULT_HEIGHT 320
static int unique = 1 ;
2013-09-11 13:57:01 +04:00
static void
set_cmd ( QXLCommandExt * ext , uint32_t type , QXLPHYSICAL data )
2013-08-05 11:26:20 +04:00
{
ext - > cmd . type = type ;
ext - > cmd . data = data ;
ext - > cmd . padding = 0 ;
ext - > group_id = MEM_SLOT_GROUP_ID ;
ext - > flags = 0 ;
}
2013-09-11 13:57:01 +04:00
static void
simple_set_release_info ( QXLReleaseInfo * info , intptr_t ptr )
2013-08-05 11:26:20 +04:00
{
info - > id = ptr ;
//info->group_id = MEM_SLOT_GROUP_ID;
}
2013-09-11 13:57:01 +04:00
/* Note: push_command/get_command are called from different threads */
2013-08-21 16:30:16 +04:00
2013-09-11 13:57:01 +04:00
static void
push_command ( SpiceScreen * spice_screen , QXLCommandExt * ext )
2013-08-21 16:30:16 +04:00
{
2013-09-11 13:57:01 +04:00
g_mutex_lock ( spice_screen - > command_mutex ) ;
2013-08-21 16:30:16 +04:00
2013-09-11 13:57:01 +04:00
while ( spice_screen - > commands_end - spice_screen - > commands_start > = COMMANDS_SIZE ) {
g_cond_wait ( spice_screen - > command_cond , spice_screen - > command_mutex ) ;
2013-08-21 16:30:16 +04:00
}
2013-09-11 13:57:01 +04:00
g_assert ( spice_screen - > commands_end - spice_screen - > commands_start < COMMANDS_SIZE ) ;
spice_screen - > commands [ spice_screen - > commands_end % COMMANDS_SIZE ] = ext ;
spice_screen - > commands_end + + ;
g_mutex_unlock ( spice_screen - > command_mutex ) ;
spice_screen - > qxl_worker - > wakeup ( spice_screen - > qxl_worker ) ;
2013-08-21 16:30:16 +04:00
}
2013-08-06 10:32:59 +04:00
/* bitmap are freed, so they must be allocated with g_malloc */
2013-09-11 13:57:01 +04:00
static SimpleSpiceUpdate *
spice_screen_update_from_bitmap_cmd ( uint32_t surface_id , QXLRect bbox , uint8_t * bitmap )
2013-08-05 11:26:20 +04:00
{
SimpleSpiceUpdate * update ;
QXLDrawable * drawable ;
QXLImage * image ;
uint32_t bw , bh ;
bh = bbox . bottom - bbox . top ;
bw = bbox . right - bbox . left ;
2013-08-06 10:32:59 +04:00
update = g_new0 ( SimpleSpiceUpdate , 1 ) ;
2013-08-05 11:26:20 +04:00
update - > bitmap = bitmap ;
drawable = & update - > drawable ;
image = & update - > image ;
drawable - > surface_id = surface_id ;
drawable - > bbox = bbox ;
2013-08-05 13:33:57 +04:00
drawable - > clip . type = SPICE_CLIP_TYPE_NONE ;
2013-08-05 11:26:20 +04:00
drawable - > effect = QXL_EFFECT_OPAQUE ;
simple_set_release_info ( & drawable - > release_info , ( intptr_t ) update ) ;
drawable - > type = QXL_DRAW_COPY ;
drawable - > surfaces_dest [ 0 ] = - 1 ;
drawable - > surfaces_dest [ 1 ] = - 1 ;
drawable - > surfaces_dest [ 2 ] = - 1 ;
drawable - > u . copy . rop_descriptor = SPICE_ROPD_OP_PUT ;
drawable - > u . copy . src_bitmap = ( intptr_t ) image ;
drawable - > u . copy . src_area . right = bw ;
drawable - > u . copy . src_area . bottom = bh ;
QXL_SET_IMAGE_ID ( image , QXL_IMAGE_GROUP_DEVICE , unique ) ;
image - > descriptor . type = SPICE_IMAGE_TYPE_BITMAP ;
image - > bitmap . flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN ;
image - > bitmap . stride = bw * 4 ;
image - > descriptor . width = image - > bitmap . x = bw ;
image - > descriptor . height = image - > bitmap . y = bh ;
image - > bitmap . data = ( intptr_t ) bitmap ;
image - > bitmap . palette = 0 ;
image - > bitmap . format = SPICE_BITMAP_FMT_32BIT ;
set_cmd ( & update - > ext , QXL_CMD_DRAW , ( intptr_t ) drawable ) ;
return update ;
}
2013-09-11 13:57:01 +04:00
static SimpleSpiceUpdate *
spice_screen_draw_char_cmd ( SpiceScreen * spice_screen , int x , int y , int c ,
int fg , int bg )
2013-08-05 11:26:20 +04:00
{
int top , left ;
uint8_t * dst ;
uint8_t * bitmap ;
int bw , bh ;
2013-08-05 14:18:05 +04:00
int i , j ;
2013-08-05 11:26:20 +04:00
QXLRect bbox ;
2013-08-05 16:18:45 +04:00
left = x * 8 ;
top = y * 16 ;
2013-08-05 11:26:20 +04:00
unique + + ;
2013-08-05 13:17:39 +04:00
bw = 8 ;
bh = 16 ;
2013-08-05 11:26:20 +04:00
2013-08-06 10:32:59 +04:00
bitmap = dst = g_malloc ( bw * bh * 4 ) ;
2013-08-05 11:26:20 +04:00
2013-08-05 14:18:05 +04:00
unsigned char * data = vt_font_data + c * 16 ;
unsigned char d = * data ;
2013-08-21 10:14:37 +04:00
g_assert ( fg > = 0 & & fg < 16 ) ;
g_assert ( bg > = 0 & & bg < 16 ) ;
unsigned char fgc_red = default_red [ fg ] ;
unsigned char fgc_blue = default_blu [ fg ] ;
unsigned char fgc_green = default_grn [ fg ] ;
unsigned char bgc_red = default_red [ bg ] ;
unsigned char bgc_blue = default_blu [ bg ] ;
unsigned char bgc_green = default_grn [ bg ] ;
2013-08-06 10:32:59 +04:00
2013-08-05 14:18:05 +04:00
for ( j = 0 ; j < 16 ; j + + ) {
for ( i = 0 ; i < 8 ; i + + ) {
if ( ( i & 7 ) = = 0 ) {
d = * data ;
data + + ;
}
if ( d & 0x80 ) {
2013-08-06 10:32:59 +04:00
* ( dst ) = fgc_blue ;
* ( dst + 1 ) = fgc_green ;
* ( dst + 2 ) = fgc_red ;
* ( dst + 3 ) = 0 ;
} else {
* ( dst ) = bgc_blue ;
* ( dst + 1 ) = bgc_green ;
* ( dst + 2 ) = bgc_red ;
2013-08-05 14:18:05 +04:00
* ( dst + 3 ) = 0 ;
}
d < < = 1 ;
dst + = 4 ;
}
2013-08-05 11:26:20 +04:00
}
bbox . left = left ; bbox . top = top ;
bbox . right = left + bw ; bbox . bottom = top + bh ;
2013-08-05 14:18:05 +04:00
2013-09-11 13:57:01 +04:00
return spice_screen_update_from_bitmap_cmd ( 0 , bbox , bitmap ) ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
void
spice_screen_scroll ( SpiceScreen * spice_screen , int x1 , int y1 ,
int x2 , int y2 , int src_x , int src_y )
2013-08-21 16:30:16 +04:00
{
SimpleSpiceUpdate * update ;
QXLDrawable * drawable ;
QXLRect bbox ;
2013-09-11 13:57:01 +04:00
int surface_id = 0 ;
2013-08-21 16:30:16 +04:00
update = g_new0 ( SimpleSpiceUpdate , 1 ) ;
drawable = & update - > drawable ;
bbox . left = x1 ;
bbox . top = y1 ;
bbox . right = x2 ;
bbox . bottom = y2 ;
drawable - > surface_id = surface_id ;
drawable - > bbox = bbox ;
drawable - > clip . type = SPICE_CLIP_TYPE_NONE ;
drawable - > effect = QXL_EFFECT_OPAQUE ;
simple_set_release_info ( & drawable - > release_info , ( intptr_t ) update ) ;
drawable - > type = QXL_COPY_BITS ;
drawable - > surfaces_dest [ 0 ] = - 1 ;
drawable - > surfaces_dest [ 1 ] = - 1 ;
drawable - > surfaces_dest [ 2 ] = - 1 ;
drawable - > u . copy_bits . src_pos . x = src_x ;
drawable - > u . copy_bits . src_pos . y = src_y ;
set_cmd ( & update - > ext , QXL_CMD_DRAW , ( intptr_t ) drawable ) ;
2013-09-11 13:57:01 +04:00
push_command ( spice_screen , & update - > ext ) ;
2013-08-21 16:30:16 +04:00
}
2013-09-11 13:57:01 +04:00
void
spice_screen_clear ( SpiceScreen * spice_screen , int x1 , int y1 , int x2 , int y2 )
2013-08-21 16:30:16 +04:00
{
SimpleSpiceUpdate * update ;
QXLDrawable * drawable ;
QXLRect bbox ;
2013-09-11 13:57:01 +04:00
int surface_id = 0 ;
2013-08-21 16:30:16 +04:00
update = g_new0 ( SimpleSpiceUpdate , 1 ) ;
drawable = & update - > drawable ;
bbox . left = x1 ;
bbox . top = y1 ;
bbox . right = x2 ;
bbox . bottom = y2 ;
drawable - > surface_id = surface_id ;
drawable - > bbox = bbox ;
drawable - > clip . type = SPICE_CLIP_TYPE_NONE ;
drawable - > effect = QXL_EFFECT_OPAQUE ;
simple_set_release_info ( & drawable - > release_info , ( intptr_t ) update ) ;
drawable - > type = QXL_DRAW_BLACKNESS ;
drawable - > surfaces_dest [ 0 ] = - 1 ;
drawable - > surfaces_dest [ 1 ] = - 1 ;
drawable - > surfaces_dest [ 2 ] = - 1 ;
set_cmd ( & update - > ext , QXL_CMD_DRAW , ( intptr_t ) drawable ) ;
2013-09-11 13:57:01 +04:00
push_command ( spice_screen , & update - > ext ) ;
2013-08-21 16:30:16 +04:00
}
2013-09-11 13:57:01 +04:00
static void
create_primary_surface ( SpiceScreen * spice_screen , uint32_t width ,
uint32_t height )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
QXLWorker * qxl_worker = spice_screen - > qxl_worker ;
2013-08-05 11:26:20 +04:00
QXLDevSurfaceCreate surface = { 0 , } ;
g_assert ( height < = MAX_HEIGHT ) ;
g_assert ( width < = MAX_WIDTH ) ;
g_assert ( height > 0 ) ;
g_assert ( width > 0 ) ;
surface . format = SPICE_SURFACE_FMT_32_xRGB ;
2013-09-11 13:57:01 +04:00
surface . width = spice_screen - > primary_width = width ;
surface . height = spice_screen - > primary_height = height ;
2013-08-05 11:26:20 +04:00
surface . stride = - width * 4 ; /* negative? */
surface . mouse_mode = TRUE ; /* unused by red_worker */
surface . flags = 0 ;
surface . type = 0 ; /* unused by red_worker */
surface . position = 0 ; /* unused by red_worker */
2013-09-11 13:57:01 +04:00
surface . mem = ( uint64_t ) & spice_screen - > primary_surface ;
2013-08-05 11:26:20 +04:00
surface . group_id = MEM_SLOT_GROUP_ID ;
2013-09-11 13:57:01 +04:00
spice_screen - > width = width ;
spice_screen - > height = height ;
2013-08-05 11:26:20 +04:00
qxl_worker - > create_primary_surface ( qxl_worker , 0 , & surface ) ;
}
QXLDevMemSlot slot = {
2013-09-11 13:57:01 +04:00
. slot_group_id = MEM_SLOT_GROUP_ID ,
. slot_id = 0 ,
. generation = 0 ,
. virt_start = 0 ,
. virt_end = ~ 0 ,
. addr_delta = 0 ,
. qxl_ram_size = ~ 0 ,
2013-08-05 11:26:20 +04:00
} ;
2013-09-11 13:57:01 +04:00
static void
attache_worker ( QXLInstance * qin , QXLWorker * _qxl_worker )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
SpiceScreen * spice_screen = SPICE_CONTAINEROF ( qin , SpiceScreen , qxl_instance ) ;
2013-08-05 11:26:20 +04:00
2013-09-11 13:57:01 +04:00
if ( spice_screen - > qxl_worker ) {
g_assert_not_reached ( ) ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
spice_screen - > qxl_worker = _qxl_worker ;
spice_screen - > qxl_worker - > add_memslot ( spice_screen - > qxl_worker , & slot ) ;
create_primary_surface ( spice_screen , DEFAULT_WIDTH , DEFAULT_HEIGHT ) ;
spice_screen - > qxl_worker - > start ( spice_screen - > qxl_worker ) ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
static void
set_compression_level ( QXLInstance * qin , int level )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
/* not used */
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
static void
set_mm_time ( QXLInstance * qin , uint32_t mm_time )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
/* not used */
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
static void
get_init_info ( QXLInstance * qin , QXLDevInitInfo * info )
2013-08-05 11:26:20 +04:00
{
memset ( info , 0 , sizeof ( * info ) ) ;
info - > num_memslots = 1 ;
info - > num_memslots_groups = 1 ;
info - > memslot_id_bits = 1 ;
info - > memslot_gen_bits = 1 ;
2013-08-05 12:45:04 +04:00
info - > n_surfaces = 1 ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
/* called from spice_server thread (i.e. red_worker thread) */
static int
get_command ( QXLInstance * qin , struct QXLCommandExt * ext )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
SpiceScreen * spice_screen = SPICE_CONTAINEROF ( qin , SpiceScreen , qxl_instance ) ;
2013-08-21 14:58:20 +04:00
int res = FALSE ;
2013-09-11 13:57:01 +04:00
g_mutex_lock ( spice_screen - > command_mutex ) ;
2013-08-21 14:58:20 +04:00
2013-09-11 13:57:01 +04:00
if ( ( spice_screen - > commands_end - spice_screen - > commands_start ) = = 0 ) {
2013-08-21 14:58:20 +04:00
res = FALSE ;
goto ret ;
2013-08-05 11:26:20 +04:00
}
2013-08-21 14:58:20 +04:00
2013-09-11 13:57:01 +04:00
* ext = * spice_screen - > commands [ spice_screen - > commands_start % COMMANDS_SIZE ] ;
g_assert ( spice_screen - > commands_start < spice_screen - > commands_end ) ;
spice_screen - > commands_start + + ;
g_cond_signal ( spice_screen - > command_cond ) ;
2013-08-21 14:58:20 +04:00
res = TRUE ;
ret :
2013-09-11 13:57:01 +04:00
g_mutex_unlock ( spice_screen - > command_mutex ) ;
2013-08-21 14:58:20 +04:00
return res ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
static int
req_cmd_notification ( QXLInstance * qin )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
//SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
//spice_screen->core->timer_start(spice_screen->wakeup_timer, spice_screen->wakeup_ms);
2013-09-10 15:05:05 +04:00
2013-08-05 11:26:20 +04:00
return TRUE ;
}
2013-08-05 15:32:03 +04:00
2013-09-11 13:57:01 +04:00
static void
release_resource ( QXLInstance * qin , struct QXLReleaseInfoExt release_info )
2013-08-05 11:26:20 +04:00
{
QXLCommandExt * ext = ( QXLCommandExt * ) ( unsigned long ) release_info . info - > id ;
2013-09-11 13:57:01 +04:00
2013-08-05 11:26:20 +04:00
g_assert ( release_info . group_id = = MEM_SLOT_GROUP_ID ) ;
switch ( ext - > cmd . type ) {
case QXL_CMD_DRAW :
2013-09-11 13:57:01 +04:00
spice_screen_destroy_update ( ( void * ) ext ) ;
2013-08-05 11:26:20 +04:00
break ;
case QXL_CMD_SURFACE :
free ( ext ) ;
break ;
case QXL_CMD_CURSOR : {
QXLCursorCmd * cmd = ( QXLCursorCmd * ) ( unsigned long ) ext - > cmd . data ;
if ( cmd - > type = = QXL_CURSOR_SET ) {
free ( cmd ) ;
}
free ( ext ) ;
break ;
}
default :
abort ( ) ;
}
}
2013-09-11 13:57:01 +04:00
# define CURSOR_WIDTH 8
# define CURSOR_HEIGHT 16
2013-08-05 11:26:20 +04:00
static struct {
QXLCursor cursor ;
uint8_t data [ CURSOR_WIDTH * CURSOR_HEIGHT * 4 ] ; // 32bit per pixel
} cursor ;
2013-09-11 13:57:01 +04:00
static void
cursor_init ( )
2013-08-05 11:26:20 +04:00
{
cursor . cursor . header . unique = 0 ;
cursor . cursor . header . type = SPICE_CURSOR_TYPE_COLOR32 ;
cursor . cursor . header . width = CURSOR_WIDTH ;
cursor . cursor . header . height = CURSOR_HEIGHT ;
cursor . cursor . header . hot_spot_x = 0 ;
cursor . cursor . header . hot_spot_y = 0 ;
cursor . cursor . data_size = CURSOR_WIDTH * CURSOR_HEIGHT * 4 ;
// X drivers addes it to the cursor size because it could be
// cursor data information or another cursor related stuffs.
// Otherwise, the code will break in client/cursor.cpp side,
// that expect the data_size plus cursor information.
// Blame cursor protocol for this. :-)
cursor . cursor . data_size + = 128 ;
cursor . cursor . chunk . data_size = cursor . cursor . data_size ;
cursor . cursor . chunk . prev_chunk = cursor . cursor . chunk . next_chunk = 0 ;
}
2013-09-11 13:57:01 +04:00
static int
get_cursor_command ( QXLInstance * qin , struct QXLCommandExt * ext )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
SpiceScreen * spice_screen = SPICE_CONTAINEROF ( qin , SpiceScreen , qxl_instance ) ;
2013-08-05 11:26:20 +04:00
static int set = 1 ;
static int x = 0 , y = 0 ;
QXLCursorCmd * cursor_cmd ;
QXLCommandExt * cmd ;
2013-09-11 13:57:01 +04:00
if ( ! spice_screen - > cursor_notify ) {
2013-08-05 11:26:20 +04:00
return FALSE ;
}
2013-09-11 13:57:01 +04:00
spice_screen - > cursor_notify - - ;
2013-08-05 11:26:20 +04:00
cmd = calloc ( sizeof ( QXLCommandExt ) , 1 ) ;
cursor_cmd = calloc ( sizeof ( QXLCursorCmd ) , 1 ) ;
cursor_cmd - > release_info . id = ( unsigned long ) cmd ;
if ( set ) {
cursor_cmd - > type = QXL_CURSOR_SET ;
cursor_cmd - > u . set . position . x = 0 ;
cursor_cmd - > u . set . position . y = 0 ;
cursor_cmd - > u . set . visible = TRUE ;
cursor_cmd - > u . set . shape = ( unsigned long ) & cursor ;
2013-09-11 13:57:01 +04:00
// white rect as cursor
2013-08-05 11:26:20 +04:00
memset ( cursor . data , 255 , sizeof ( cursor . data ) ) ;
set = 0 ;
} else {
cursor_cmd - > type = QXL_CURSOR_MOVE ;
2013-09-11 13:57:01 +04:00
cursor_cmd - > u . position . x = x + + % spice_screen - > primary_width ;
cursor_cmd - > u . position . y = y + + % spice_screen - > primary_height ;
2013-08-05 11:26:20 +04:00
}
cmd - > cmd . data = ( unsigned long ) cursor_cmd ;
cmd - > cmd . type = QXL_CMD_CURSOR ;
cmd - > group_id = MEM_SLOT_GROUP_ID ;
cmd - > flags = 0 ;
* ext = * cmd ;
2013-09-11 13:57:01 +04:00
2013-08-05 11:26:20 +04:00
return TRUE ;
}
2013-09-11 13:57:01 +04:00
static int
req_cursor_notification ( QXLInstance * qin )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
/* not used */
2013-08-05 11:26:20 +04:00
return TRUE ;
}
2013-09-11 13:57:01 +04:00
static void
notify_update ( QXLInstance * qin , uint32_t update_id )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
/* not used */
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
static int
flush_resources ( QXLInstance * qin )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
/* not used */
2013-08-05 11:26:20 +04:00
return TRUE ;
}
2013-09-11 13:57:01 +04:00
static int
client_monitors_config ( QXLInstance * qin , VDAgentMonitorsConfig * monitors_config )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
/* not used */
2013-08-05 11:26:20 +04:00
return 0 ;
}
2013-09-11 13:57:01 +04:00
static void
set_client_capabilities ( QXLInstance * qin , uint8_t client_present ,
uint8_t caps [ 58 ] )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
SpiceScreen * spice_screen = SPICE_CONTAINEROF ( qin , SpiceScreen , qxl_instance ) ;
2013-08-05 11:26:20 +04:00
2013-09-11 14:56:28 +04:00
DPRINTF ( 1 , " %s: present %d caps %d " , __func__ , client_present , caps [ 0 ] ) ;
2013-09-11 13:57:01 +04:00
if ( spice_screen - > on_client_connected & & client_present ) {
spice_screen - > on_client_connected ( spice_screen ) ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
if ( spice_screen - > on_client_disconnected & & ! client_present ) {
spice_screen - > on_client_disconnected ( spice_screen ) ;
2013-08-05 11:26:20 +04:00
}
}
2013-08-05 15:22:02 +04:00
static int client_count = 0 ;
2013-09-11 13:57:01 +04:00
static void
client_connected ( SpiceScreen * spice_screen )
2013-08-05 15:22:02 +04:00
{
client_count + + ;
2013-09-11 14:56:28 +04:00
DPRINTF ( 1 , " %s: client_count = %d " , __func__ , client_count ) ;
2013-08-05 15:22:02 +04:00
}
2013-09-11 13:57:01 +04:00
static void
client_disconnected ( SpiceScreen * spice_screen )
2013-08-05 15:22:02 +04:00
{
if ( client_count > 0 ) {
client_count - - ;
2013-09-11 14:56:28 +04:00
DPRINTF ( 1 , " %s: client_count = %d " , __func__ , client_count ) ;
2013-08-05 15:22:02 +04:00
exit ( 0 ) ; // fixme: cleanup?
}
}
2013-09-11 13:57:01 +04:00
static void
do_conn_timeout ( void * opaque )
2013-08-05 15:32:03 +04:00
{
2013-09-11 13:57:01 +04:00
// SpiceScreen *spice_screen = opaque;
2013-08-05 15:32:03 +04:00
if ( client_count < = 0 ) {
2013-09-11 14:56:28 +04:00
printf ( " connection timeout - stopping server \n " ) ;
2013-08-05 15:32:03 +04:00
exit ( 0 ) ; // fixme: cleanup?
}
}
2013-08-05 11:26:20 +04:00
QXLInterface display_sif = {
. base = {
. type = SPICE_INTERFACE_QXL ,
2013-09-11 13:57:01 +04:00
. description = " spiceterm display server " ,
2013-08-05 11:26:20 +04:00
. major_version = SPICE_INTERFACE_QXL_MAJOR ,
. minor_version = SPICE_INTERFACE_QXL_MINOR
} ,
. attache_worker = attache_worker ,
. set_compression_level = set_compression_level ,
. set_mm_time = set_mm_time ,
. get_init_info = get_init_info ,
/* the callbacks below are called from spice server thread context */
. get_command = get_command ,
. req_cmd_notification = req_cmd_notification ,
. release_resource = release_resource ,
. get_cursor_command = get_cursor_command ,
. req_cursor_notification = req_cursor_notification ,
. notify_update = notify_update ,
. flush_resources = flush_resources ,
. client_monitors_config = client_monitors_config ,
. set_client_capabilities = set_client_capabilities ,
} ;
2013-09-11 13:57:01 +04:00
void
spice_screen_add_display_interface ( SpiceScreen * spice_screen )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
spice_server_add_interface ( spice_screen - > server , & spice_screen - > qxl_instance . base ) ;
2013-08-05 11:26:20 +04:00
}
2013-09-11 13:57:01 +04:00
/* vdagent interface - not sure why we need that? */
static int
vmc_write ( SpiceCharDeviceInstance * sin , const uint8_t * buf , int len )
2013-08-05 11:26:20 +04:00
{
return len ;
}
2013-09-11 13:57:01 +04:00
static int
vmc_read ( SpiceCharDeviceInstance * sin , uint8_t * buf , int len )
2013-08-05 11:26:20 +04:00
{
return 0 ;
}
2013-09-11 13:57:01 +04:00
static void
vmc_state ( SpiceCharDeviceInstance * sin , int connected )
2013-08-05 11:26:20 +04:00
{
2013-09-11 13:57:01 +04:00
2013-08-05 11:26:20 +04:00
}
static SpiceCharDeviceInterface vdagent_sif = {
. base . type = SPICE_INTERFACE_CHAR_DEVICE ,
2013-09-11 13:57:01 +04:00
. base . description = " spice virtual channel char device " ,
2013-08-05 11:26:20 +04:00
. 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 ,
} ;
SpiceCharDeviceInstance vdagent_sin = {
. base = {
. sif = & vdagent_sif . base ,
} ,
. subtype = " vdagent " ,
} ;
2013-09-11 13:57:01 +04:00
void
spice_screen_add_agent_interface ( SpiceServer * server )
2013-08-05 11:26:20 +04:00
{
spice_server_add_interface ( server , & vdagent_sin . base ) ;
}
2013-09-11 13:57:01 +04:00
void
2013-09-11 15:15:53 +04:00
spice_screen_draw_char ( SpiceScreen * spice_screen , int x , int y , gunichar2 ch , TextAttributes attrib )
2013-08-06 12:58:17 +04:00
{
int fg , bg ;
if ( attrib . invers ) {
bg = attrib . fgcol ;
fg = attrib . bgcol ;
} else {
bg = attrib . bgcol ;
fg = attrib . fgcol ;
}
if ( attrib . bold ) {
fg + = 8 ;
}
// unsuported attributes = (attrib.blink || attrib.unvisible)
2013-09-11 13:57:01 +04:00
// fixme:
2013-08-06 12:58:17 +04:00
//if (attrib.uline) {
//rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg);
//}
2013-09-10 15:05:05 +04:00
int c = vt_fontmap [ ch ] ;
2013-08-06 12:58:17 +04:00
SimpleSpiceUpdate * update ;
2013-09-11 13:57:01 +04:00
update = spice_screen_draw_char_cmd ( spice_screen , x , y , c , fg , bg ) ;
push_command ( spice_screen , & update - > ext ) ;
2013-08-06 12:58:17 +04:00
}
2013-09-11 13:57:01 +04:00
SpiceScreen *
spice_screen_new ( SpiceCoreInterface * core )
2013-08-05 11:26:20 +04:00
{
int port = 5912 ;
2013-09-11 13:57:01 +04:00
SpiceScreen * spice_screen = g_new0 ( SpiceScreen , 1 ) ;
2013-08-05 11:26:20 +04:00
SpiceServer * server = spice_server_new ( ) ;
2013-09-11 13:57:01 +04:00
spice_screen - > command_cond = g_cond_new ( ) ;
spice_screen - > command_mutex = g_mutex_new ( ) ;
2013-08-21 14:58:20 +04:00
2013-09-11 13:57:01 +04:00
spice_screen - > on_client_connected = client_connected ,
spice_screen - > on_client_disconnected = client_disconnected ,
2013-08-05 15:22:02 +04:00
2013-09-11 13:57:01 +04:00
spice_screen - > qxl_instance . base . sif = & display_sif . base ;
spice_screen - > qxl_instance . id = 0 ;
2013-08-05 11:26:20 +04:00
2013-09-11 13:57:01 +04:00
spice_screen - > core = core ;
spice_screen - > server = server ;
spice_screen - > cursor_notify = NOTIFY_CURSOR_BATCH ;
printf ( " listening on port %d (unsecure) \n " , port ) ;
2013-08-05 16:18:45 +04:00
2013-08-05 11:26:20 +04:00
spice_server_set_port ( server , port ) ;
spice_server_set_noauth ( server ) ;
2013-09-11 13:57:01 +04:00
2013-08-05 11:56:02 +04:00
int res = spice_server_init ( server , core ) ;
if ( res ! = 0 ) {
g_error ( " spice_server_init failed, res = %d \n " , res ) ;
}
2013-08-05 11:26:20 +04:00
cursor_init ( ) ;
2013-08-05 15:32:03 +04:00
int timeout = 10 ; // max time to wait for client connection
2013-09-11 13:57:01 +04:00
spice_screen - > conn_timeout_timer = core - > timer_add ( do_conn_timeout , spice_screen ) ;
spice_screen - > core - > timer_start ( spice_screen - > conn_timeout_timer , timeout * 1000 ) ;
2013-08-05 15:32:03 +04:00
2013-09-11 13:57:01 +04:00
return spice_screen ;
2013-08-05 11:26:20 +04:00
}