/*
- Copyright (C) 2013 Proxmox Server Solutions GmbH
+ Copyright (C) 2013 - 2021 Proxmox Server Solutions GmbH
Copyright: spiceterm is under GNU GPL, the GNU General Public License.
#include "spiceterm.h"
static int debug = 0;
-
+
#define DPRINTF(x, format, ...) { \
if (x <= debug) { \
printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
/* Parts cribbed from spice-display.h/.c/qxl.c */
-typedef struct SimpleSpiceUpdate {
+typedef struct __attribute__ ((__packed__)) SimpleSpiceUpdate {
QXLCommandExt ext; // needs to be first member
QXLDrawable drawable;
QXLImage image;
int cache_id; // do not free bitmap if cache_id != 0
} SimpleSpiceUpdate;
-static void
+static void
spice_screen_destroy_update(SimpleSpiceUpdate *update)
{
if (!update) {
g_free(update);
}
-static void
+static void
release_qxl_command_ext(QXLCommandExt *ext)
{
g_assert(ext != NULL);
switch (ext->cmd.type) {
- case QXL_CMD_DRAW:
- spice_screen_destroy_update((void*)ext);
- 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);
+ case QXL_CMD_DRAW:
+ spice_screen_destroy_update((void*)ext);
+ 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;
}
- free(ext);
- break;
- }
- default:
- abort();
+ default:
+ abort();
}
}
-static void
+static void
release_resource(QXLInstance *qin, struct QXLReleaseInfoExt release_info)
{
QXLCommandExt *ext = (QXLCommandExt*)(unsigned long)release_info.info->id;
static int unique = 0x0ffff + 1;
-static void
+static void
set_cmd(QXLCommandExt *ext, uint32_t type, QXLPHYSICAL data)
{
ext->cmd.type = type;
ext->flags = 0;
}
-static void
+static void
simple_set_release_info(QXLReleaseInfo *info, intptr_t ptr)
{
info->id = ptr;
/* Note: push_command/get_command are called from different threads */
-static void
+static void
push_command(SpiceScreen *spice_screen, QXLCommandExt *ext)
{
int need_wakeup = 1;
/* bitmap are freed, so they must be allocated with g_malloc */
static SimpleSpiceUpdate *
-spice_screen_update_from_bitmap_cmd(uint32_t surface_id, QXLRect bbox, uint8_t *bitmap, int cache_id)
-{
+spice_screen_update_from_bitmap_cmd(
+ uint32_t surface_id,
+ QXLRect bbox,
+ uint8_t *bitmap,
+ int cache_id
+) {
SimpleSpiceUpdate *update;
QXLDrawable *drawable;
QXLImage *image;
}
static SimpleSpiceUpdate *
-spice_screen_draw_char_cmd(SpiceScreen *spice_screen, int x, int y, int c,
- int fg, int bg, gboolean uline)
-{
- int top, left;
- uint8_t *dst;
+spice_screen_draw_char_cmd(
+ SpiceScreen *spice_screen,
+ int x,
+ int y,
+ int c,
+ int fg,
+ int bg,
+ gboolean uline
+) {
uint8_t *bitmap = NULL;
- int bw, bh;
- int i, j;
QXLRect bbox;
int cache_id = 0;
CachedImage *ce;
}
}
- left = x*8;
- top = y*16;
-
- bw = 8;
- bh = 16;
+ int bw = 8, bh = 16;
+ int left = x * bw, top = y * bh;
if (!bitmap) {
- bitmap = dst = g_malloc(bw * bh * 4);
-
+ uint8_t *dst = bitmap = g_malloc(bw * bh * 4);
+
unsigned char *data = vt_font_data + c*16;
unsigned char d = *data;
unsigned char bgc_blue = default_blu[color_table[bg]];
unsigned char bgc_green = default_grn[color_table[bg]];
- for (j = 0; j < 16; j++) {
+ for (int j = 0; j < 16; j++) {
gboolean ul = (j == 14) && uline;
- for (i = 0; i < 8; i++) {
+ for (int i = 0; i < 8; i++) {
if (i == 0) {
d=*data;
data++;
}
if (ul || d&0x80) {
- *(dst) = fgc_blue;
+ *(dst+0) = fgc_blue;
*(dst+1) = fgc_green;
*(dst+2) = fgc_red;
*(dst+3) = 0;
} else {
- *(dst) = bgc_blue;
+ *(dst+0) = bgc_blue;
*(dst+1) = bgc_green;
*(dst+2) = bgc_red;
*(dst+3) = 0;
}
- d<<=1;
+ d <<= 1;
dst += 4;
}
}
- if (cache_id != 0) {
- ce = g_new(CachedImage, 1);
- ce->cache_id = cache_id;
- ce->bitmap = bitmap;
- g_hash_table_insert(spice_screen->image_cache, &ce->cache_id, ce);
- }
+ if (cache_id != 0) {
+ ce = g_new(CachedImage, 1);
+ ce->cache_id = cache_id;
+ ce->bitmap = bitmap;
+ g_hash_table_insert(spice_screen->image_cache, &ce->cache_id, ce);
+ }
}
bbox.left = left; bbox.top = top;
return spice_screen_update_from_bitmap_cmd(0, bbox, bitmap, cache_id);
}
-void
-spice_screen_scroll(SpiceScreen *spice_screen, int x1, int y1,
- int x2, int y2, int src_x, int src_y)
-{
+void
+spice_screen_scroll(
+ SpiceScreen *spice_screen,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int src_x,
+ int src_y
+) {
SimpleSpiceUpdate *update;
QXLDrawable *drawable;
QXLRect bbox;
push_command(spice_screen, &update->ext);
}
-void
+void
spice_screen_clear(SpiceScreen *spice_screen, int x1, int y1, int x2, int y2)
{
SimpleSpiceUpdate *update;
push_command(spice_screen, &update->ext);
}
-static void
-create_primary_surface(SpiceScreen *spice_screen, uint32_t width,
- uint32_t height)
-{
+static void
+create_primary_surface(
+ SpiceScreen *spice_screen,
+ uint32_t width,
+ uint32_t height
+) {
QXLDevSurfaceCreate surface = { 0, };
g_assert(height > 0);
.qxl_ram_size = ~0,
};
-static void
+static void
attache_worker(QXLInstance *qin, QXLWorker *_qxl_worker)
{
SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
if (spice_screen->qxl_worker) {
g_assert_not_reached();
}
-
+
spice_screen->qxl_worker = _qxl_worker;
spice_qxl_add_memslot(&spice_screen->qxl_instance, &slot);
create_primary_surface(spice_screen, spice_screen->width, spice_screen->height);
spice_server_vm_start(spice_screen->server);
}
-static void
+static void
set_compression_level(QXLInstance *qin, int level)
{
/* not used */
}
-static void
+static void
set_mm_time(QXLInstance *qin, uint32_t mm_time)
{
/* not used */
}
-static void
+static void
get_init_info(QXLInstance *qin, QXLDevInitInfo *info)
{
memset(info, 0, sizeof(*info));
}
/* called from spice_server thread (i.e. red_worker thread) */
-static int
+static int
get_command(QXLInstance *qin, struct QXLCommandExt *ext)
{
SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
int res = FALSE;
g_mutex_lock(&spice_screen->command_mutex);
-
+
if ((spice_screen->commands_end - spice_screen->commands_start) == 0) {
res = FALSE;
goto ret;
}
void
-discard_pending_commands(SpiceScreen *spice_screen)
+discard_pending_commands(SpiceScreen *spice_screen)
{
int pos;
g_mutex_unlock(&spice_screen->command_mutex);
}
-static int
+static int
req_cmd_notification(QXLInstance *qin)
{
//SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
uint8_t data[CURSOR_WIDTH * CURSOR_HEIGHT * 4]; // 32bit per pixel
} cursor;
-static void
+static void
cursor_init()
{
cursor.cursor.header.unique = 0;
cursor.cursor.chunk.prev_chunk = cursor.cursor.chunk.next_chunk = 0;
}
-static int
+static int
get_cursor_command(QXLInstance *qin, struct QXLCommandExt *ext)
{
SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
-
+
QXLCursorCmd *cursor_cmd;
QXLCommandExt *cmd;
- if (spice_screen->cursor_set)
+ if (spice_screen->cursor_set)
return FALSE;
-
+
spice_screen->cursor_set = 1;
-
+
cmd = calloc(sizeof(QXLCommandExt), 1);
cursor_cmd = calloc(sizeof(QXLCursorCmd), 1);
return TRUE;
}
-static int
+static int
req_cursor_notification(QXLInstance *qin)
{
/* not used */
return TRUE;
}
-static void
+static void
notify_update(QXLInstance *qin, uint32_t update_id)
{
/* not used */
}
-static int
+static int
flush_resources(QXLInstance *qin)
{
/* not used */
return TRUE;
}
-static int
+static int
client_monitors_config(QXLInstance *qin, VDAgentMonitorsConfig *monitors_config)
{
/* not used */
return 0;
}
-static void
-set_client_capabilities(QXLInstance *qin, uint8_t client_present,
- uint8_t caps[58])
-{
+static void
+set_client_capabilities(
+ QXLInstance *qin,
+ uint8_t client_present,
+ uint8_t caps[58]
+) {
SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
DPRINTF(1, "present %d caps %d", client_present, caps[0]);
static int client_count = 0;
-static void
+static void
client_connected(SpiceScreen *spice_screen)
{
client_count++;
DPRINTF(1, "client_count = %d", client_count);
}
-static void
+static void
client_disconnected(SpiceScreen *spice_screen)
-{
+{
if (client_count > 0) {
client_count--;
DPRINTF(1, "client_count = %d", client_count);
}
}
-static void
+static void
do_conn_timeout(void *opaque)
{
// SpiceScreen *spice_screen = opaque;
};
-void
-spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar2 ch,
- TextAttributes attrib)
-{
+void
+spice_screen_draw_char(
+ SpiceScreen *spice_screen,
+ int x,
+ int y,
+ gunichar2 ch,
+ TextAttributes attrib
+) {
int fg, bg;
int invers;
invers = attrib.selected ? 0 : 1;
} else {
invers = attrib.selected ? 1 : 0;
- }
+ }
if (invers) {
bg = attrib.fgcol;
}
SpiceScreen *
-spice_screen_new(SpiceCoreInterface *core, uint32_t width, uint32_t height,
- SpiceTermOptions *opts)
-{
+spice_screen_new(
+ SpiceCoreInterface *core,
+ uint32_t width,
+ uint32_t height,
+ SpiceTermOptions *opts
+) {
SpiceScreen *spice_screen = g_new0(SpiceScreen, 1);
SpiceServer* server = spice_server_new();
char *x509_key_file = "/etc/pve/local/pve-ssl.key";
// spice_server_set_port(spice_server, port);
//spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF);
- spice_server_set_tls(server, opts->port,
- x509_cacert_file,
- x509_cert_file,
- x509_key_file,
- x509_key_password,
- x509_dh_file,
- tls_ciphers);
+ spice_server_set_tls(
+ server, opts->port,
+ x509_cacert_file,
+ x509_cert_file,
+ x509_key_file,
+ x509_key_password,
+ x509_dh_file,
+ tls_ciphers
+ );
if (opts->noauth) {
spice_server_set_noauth(server);
}
}
+ spice_server_set_exit_on_disconnect(server, 1);
+
int res = spice_server_init(server, core);
if (res != 0) {
g_error("spice_server_init failed, res = %d\n", res);
return spice_screen;
}
-void
-spice_screen_resize(SpiceScreen *spice_screen, uint32_t width,
- uint32_t height)
-{
+void
+spice_screen_resize(
+ SpiceScreen *spice_screen,
+ uint32_t width,
+ uint32_t height
+) {
if (spice_screen->width == width && spice_screen->height == height) {
return;
}
discard_pending_commands(spice_screen);
spice_qxl_destroy_primary_surface(&spice_screen->qxl_instance, 0);
-
+
create_primary_surface(spice_screen, width, height);
spice_screen_clear(spice_screen, 0, 0, width, height);