#include <spice/enums.h>
#include <spice/macros.h>
#include <spice/qxl_dev.h>
+#include <spice/vd_agent.h>
#include "glyphs.h"
#include "spiceterm.h"
+static int debug = 0;
+
+#define DPRINTF(x, format, ...) { \
+ if (x <= debug) { \
+ printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
+ } \
+}
+
#define MEM_SLOT_GROUP_ID 0
#define NOTIFY_DISPLAY_BATCH (SINGLE_PART/2)
/* Parts cribbed from spice-display.h/.c/qxl.c */
typedef struct SimpleSpiceUpdate {
- QXLCommandExt ext; // first
+ QXLCommandExt ext; // needs to be first member
QXLDrawable drawable;
QXLImage image;
uint8_t *bitmap;
+ int cache_id; // do not free bitmap if cache_id != 0
} SimpleSpiceUpdate;
static void
uint8_t *ptr = (uint8_t*)update->drawable.clip.data;
free(ptr);
}
- g_free(update->bitmap);
+ if (update->bitmap && !update->cache_id) {
+ g_free(update->bitmap);
+ }
+
g_free(update);
}
-#define DEFAULT_WIDTH 640
-#define DEFAULT_HEIGHT 320
-
-static int unique = 1;
+static int unique = 0x0ffff + 1;
static void
set_cmd(QXLCommandExt *ext, uint32_t type, QXLPHYSICAL data)
static void
push_command(SpiceScreen *spice_screen, QXLCommandExt *ext)
{
+ int need_wakeup = 1;
+
g_mutex_lock(spice_screen->command_mutex);
while (spice_screen->commands_end - spice_screen->commands_start >= COMMANDS_SIZE) {
g_assert(spice_screen->commands_end - spice_screen->commands_start < COMMANDS_SIZE);
+ if ((spice_screen->commands_end - spice_screen->commands_start) > 0) {
+ need_wakeup = 0;
+ }
+
spice_screen->commands[spice_screen->commands_end % COMMANDS_SIZE] = ext;
spice_screen->commands_end++;
+ if (need_wakeup) {
+ spice_screen->qxl_worker->wakeup(spice_screen->qxl_worker);
+ }
+
g_mutex_unlock(spice_screen->command_mutex);
- spice_screen->qxl_worker->wakeup(spice_screen->qxl_worker);
}
/* 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)
+spice_screen_update_from_bitmap_cmd(uint32_t surface_id, QXLRect bbox, uint8_t *bitmap, int cache_id)
{
SimpleSpiceUpdate *update;
QXLDrawable *drawable;
drawable->u.copy.src_area.right = bw;
drawable->u.copy.src_area.bottom = bh;
- QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, unique);
+ if (cache_id) {
+ QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, cache_id);
+ image->descriptor.flags = SPICE_IMAGE_FLAGS_CACHE_ME;
+ update->cache_id = cache_id;
+ } else {
+ 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;
static SimpleSpiceUpdate *
spice_screen_draw_char_cmd(SpiceScreen *spice_screen, int x, int y, int c,
- int fg, int bg)
+ int fg, int bg, gboolean uline)
{
int top, left;
uint8_t *dst;
- uint8_t *bitmap;
+ uint8_t *bitmap = NULL;
int bw, bh;
int i, j;
QXLRect bbox;
+ int cache_id = 0;
+ CachedImage *ce;
+
+ if (!uline && c < 256) {
+ cache_id = ((fg << 12) | (bg << 8) | (c & 255)) & 0x0ffff;
+ if ((ce = (CachedImage *)g_hash_table_lookup(spice_screen->image_cache, &cache_id))) {
+ bitmap = ce->bitmap;
+ }
+ }
left = x*8;
top = y*16;
- unique++;
-
bw = 8;
bh = 16;
- bitmap = dst = g_malloc(bw * bh * 4);
-
- unsigned char *data = vt_font_data + c*16;
- unsigned char d = *data;
-
- 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];
-
- for (j = 0; j < 16; j++) {
- for (i = 0; i < 8; i++) {
- if ((i&7) == 0) {
- d=*data;
- data++;
+ if (!bitmap) {
+ bitmap = dst = g_malloc(bw * bh * 4);
+
+ unsigned char *data = vt_font_data + c*16;
+ unsigned char d = *data;
+
+ 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];
+
+ for (j = 0; j < 16; j++) {
+ gboolean ul = (j == 14) && uline;
+ for (i = 0; i < 8; i++) {
+ if (i == 0) {
+ d=*data;
+ data++;
+ }
+ if (ul || d&0x80) {
+ *(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;
+ *(dst+3) = 0;
+ }
+ d<<=1;
+ dst += 4;
}
- if (d&0x80) {
- *(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;
- *(dst+3) = 0;
- }
- d<<=1;
- dst += 4;
}
+ 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;
bbox.right = left + bw; bbox.bottom = top + bh;
- return spice_screen_update_from_bitmap_cmd(0, bbox, bitmap);
+ return spice_screen_update_from_bitmap_cmd(0, bbox, bitmap, cache_id);
}
void
QXLWorker *qxl_worker = spice_screen->qxl_worker;
QXLDevSurfaceCreate surface = { 0, };
- g_assert(height <= MAX_HEIGHT);
- g_assert(width <= MAX_WIDTH);
g_assert(height > 0);
g_assert(width > 0);
+ if (height > MAX_HEIGHT)
+ height = MAX_HEIGHT;
+
+ if (width > MAX_WIDTH)
+ width = MAX_WIDTH;
+
+
surface.format = SPICE_SURFACE_FMT_32_xRGB;
surface.width = spice_screen->primary_width = width;
surface.height = spice_screen->primary_height = height;
qxl_worker->create_primary_surface(qxl_worker, 0, &surface);
}
+void
+spice_screen_resize(SpiceScreen *spice_screen, uint32_t width,
+ uint32_t height)
+{
+ QXLWorker *qxl_worker = spice_screen->qxl_worker;
+
+ if (spice_screen->width == width && spice_screen->height == height) {
+ return;
+ }
+
+ qxl_worker->destroy_primary_surface(qxl_worker, 0);
+
+ create_primary_surface(spice_screen, width, height);
+}
+
+
QXLDevMemSlot slot = {
.slot_group_id = MEM_SLOT_GROUP_ID,
.slot_id = 0,
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);
+ create_primary_surface(spice_screen, spice_screen->width, spice_screen->height);
spice_screen->qxl_worker->start(spice_screen->qxl_worker);
}
{
SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance);
- printf("%s: present %d caps %d\n", __func__, client_present, caps[0]);
+ DPRINTF(1, "present %d caps %d", client_present, caps[0]);
if (spice_screen->on_client_connected && client_present) {
spice_screen->on_client_connected(spice_screen);
static void
client_connected(SpiceScreen *spice_screen)
{
- printf("Client connected\n");
client_count++;
+
+ DPRINTF(1, "client_count = %d", client_count);
}
static void
client_disconnected(SpiceScreen *spice_screen)
{
-
if (client_count > 0) {
client_count--;
- printf("Client disconnected\n");
+ DPRINTF(1, "client_count = %d", client_count);
exit(0); // fixme: cleanup?
}
}
// SpiceScreen *spice_screen = opaque;
if (client_count <= 0) {
- printf("connection timeout\n");
+ printf("connection timeout - stopping server\n");
exit (0); // fixme: cleanup?
}
}
.set_client_capabilities = set_client_capabilities,
};
-void
-spice_screen_add_display_interface(SpiceScreen* spice_screen)
-{
- spice_server_add_interface(spice_screen->server, &spice_screen->qxl_instance.base);
-}
-
-/* vdagent interface - not sure why we need that? */
-static int
-vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
-{
- return len;
-}
-
-static int
-vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
-{
- return 0;
-}
-
-static void
-vmc_state(SpiceCharDeviceInstance *sin, int connected)
-{
-
-}
-
-static SpiceCharDeviceInterface 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,
-};
-
-SpiceCharDeviceInstance vdagent_sin = {
- .base = {
- .sif = &vdagent_sif.base,
- },
- .subtype = "vdagent",
-};
-
-void
-spice_screen_add_agent_interface(SpiceServer *server)
-{
- spice_server_add_interface(server, &vdagent_sin.base);
-}
void
-spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar ch, TextAttributes attrib)
+spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar2 ch,
+ TextAttributes attrib)
{
int fg, bg;
+ int invers;
if (attrib.invers) {
+ invers = attrib.selected ? 0 : 1;
+ } else {
+ invers = attrib.selected ? 1 : 0;
+ }
+
+ if (invers) {
bg = attrib.fgcol;
fg = attrib.bgcol;
} else {
// unsuported attributes = (attrib.blink || attrib.unvisible)
- // fixme:
- //if (attrib.uline) {
- //rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg);
- //}
-
int c = vt_fontmap[ch];
SimpleSpiceUpdate *update;
- update = spice_screen_draw_char_cmd(spice_screen, x, y, c, fg, bg);
+ update = spice_screen_draw_char_cmd(spice_screen, x, y, c, fg, bg, attrib.uline);
push_command(spice_screen, &update->ext);
}
SpiceScreen *
-spice_screen_new(SpiceCoreInterface *core)
+spice_screen_new(SpiceCoreInterface *core, uint32_t width, uint32_t height, guint timeout)
{
int port = 5912;
SpiceScreen *spice_screen = g_new0(SpiceScreen, 1);
SpiceServer* server = spice_server_new();
+ spice_screen->width = width;
+ spice_screen->height = height;
+
spice_screen->command_cond = g_cond_new();
spice_screen->command_mutex = g_mutex_new();
cursor_init();
- int timeout = 10; // max time to wait for client connection
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);
+ spice_server_add_interface(spice_screen->server, &spice_screen->qxl_instance.base);
+
return spice_screen;
}