8 #include <sys/select.h>
13 #include <spice/macros.h>
14 #include <spice/qxl_dev.h>
16 #include "test_display_base.h"
17 //#include "red_channel.h"
19 #define MEM_SLOT_GROUP_ID 0
21 #define NOTIFY_DISPLAY_BATCH (SINGLE_PART/2)
22 #define NOTIFY_CURSOR_BATCH 10
24 /* Parts cribbed from spice-display.h/.c/qxl.c */
26 typedef struct SimpleSpiceUpdate
{
27 QXLCommandExt ext
; // first
33 typedef struct SimpleSurfaceCmd
{
34 QXLCommandExt ext
; // first
35 QXLSurfaceCmd surface_cmd
;
38 static void test_spice_destroy_update(SimpleSpiceUpdate
*update
)
43 if (update
->drawable
.clip
.type
!= SPICE_CLIP_TYPE_NONE
) {
44 uint8_t *ptr
= (uint8_t*)update
->drawable
.clip
.data
;
51 #define DEFAULT_WIDTH 640
52 #define DEFAULT_HEIGHT 320
55 static const int angle_parts
= 64 / SINGLE_PART
;
56 static int unique
= 1;
57 static int color
= -1;
60 __attribute__((noreturn
))
61 static void sigchld_handler(int signal_num
) // wait for the child process and exit
68 static void set_cmd(QXLCommandExt
*ext
, uint32_t type
, QXLPHYSICAL data
)
73 ext
->group_id
= MEM_SLOT_GROUP_ID
;
77 static void simple_set_release_info(QXLReleaseInfo
*info
, intptr_t ptr
)
80 //info->group_id = MEM_SLOT_GROUP_ID;
89 static void path_init(Path
*path
, int min
, int max
)
96 static void path_progress(Path
*path
)
98 path
->t
= (path
->t
+1)% (path
->max_t
- path
->min_t
) + path
->min_t
;
103 static void draw_pos(Test
*test
, int t
, int *x
, int *y
)
106 *y
= test
->primary_height
/2 + (test
->primary_height
/3)*cos(t
*2*M_PI
/angle_parts
);
107 *x
= test
->primary_width
/2 + (test
->primary_width
/3)*sin(t
*2*M_PI
/angle_parts
);
109 *y
= test
->primary_height
*(t
% SINGLE_PART
)/SINGLE_PART
;
110 *x
= ((test
->primary_width
/SINGLE_PART
)*(t
/ SINGLE_PART
)) % test
->primary_width
;
114 /* bitmap and rects are freed, so they must be allocated with malloc */
115 SimpleSpiceUpdate
*test_spice_create_update_from_bitmap(uint32_t surface_id
,
118 uint32_t num_clip_rects
,
121 SimpleSpiceUpdate
*update
;
122 QXLDrawable
*drawable
;
126 bh
= bbox
.bottom
- bbox
.top
;
127 bw
= bbox
.right
- bbox
.left
;
129 update
= calloc(sizeof(*update
), 1);
130 update
->bitmap
= bitmap
;
131 drawable
= &update
->drawable
;
132 image
= &update
->image
;
134 drawable
->surface_id
= surface_id
;
136 drawable
->bbox
= bbox
;
137 if (num_clip_rects
== 0) {
138 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
140 QXLClipRects
*cmd_clip
;
142 cmd_clip
= calloc(sizeof(QXLClipRects
) + num_clip_rects
*sizeof(QXLRect
), 1);
143 cmd_clip
->num_rects
= num_clip_rects
;
144 cmd_clip
->chunk
.data_size
= num_clip_rects
*sizeof(QXLRect
);
145 cmd_clip
->chunk
.prev_chunk
= cmd_clip
->chunk
.next_chunk
= 0;
146 memcpy(cmd_clip
+ 1, clip_rects
, cmd_clip
->chunk
.data_size
);
148 drawable
->clip
.type
= SPICE_CLIP_TYPE_RECTS
;
149 drawable
->clip
.data
= (intptr_t)cmd_clip
;
153 drawable
->effect
= QXL_EFFECT_OPAQUE
;
154 simple_set_release_info(&drawable
->release_info
, (intptr_t)update
);
155 drawable
->type
= QXL_DRAW_COPY
;
156 drawable
->surfaces_dest
[0] = -1;
157 drawable
->surfaces_dest
[1] = -1;
158 drawable
->surfaces_dest
[2] = -1;
160 drawable
->u
.copy
.rop_descriptor
= SPICE_ROPD_OP_PUT
;
161 drawable
->u
.copy
.src_bitmap
= (intptr_t)image
;
162 drawable
->u
.copy
.src_area
.right
= bw
;
163 drawable
->u
.copy
.src_area
.bottom
= bh
;
165 QXL_SET_IMAGE_ID(image
, QXL_IMAGE_GROUP_DEVICE
, unique
);
166 image
->descriptor
.type
= SPICE_IMAGE_TYPE_BITMAP
;
167 image
->bitmap
.flags
= QXL_BITMAP_DIRECT
| QXL_BITMAP_TOP_DOWN
;
168 image
->bitmap
.stride
= bw
* 4;
169 image
->descriptor
.width
= image
->bitmap
.x
= bw
;
170 image
->descriptor
.height
= image
->bitmap
.y
= bh
;
171 image
->bitmap
.data
= (intptr_t)bitmap
;
172 image
->bitmap
.palette
= 0;
173 image
->bitmap
.format
= SPICE_BITMAP_FMT_32BIT
;
175 set_cmd(&update
->ext
, QXL_CMD_DRAW
, (intptr_t)drawable
);
180 static SimpleSpiceUpdate
*test_spice_create_update_solid(uint32_t surface_id
, QXLRect bbox
, uint32_t color
)
188 bw
= bbox
.right
- bbox
.left
;
189 bh
= bbox
.bottom
- bbox
.top
;
191 bitmap
= malloc(bw
* bh
* 4);
192 dst
= (uint32_t *)bitmap
;
194 for (i
= 0 ; i
< bh
* bw
; ++i
, ++dst
) {
198 return test_spice_create_update_from_bitmap(surface_id
, bbox
, bitmap
, 0, NULL
);
201 static SimpleSpiceUpdate
*test_spice_create_update_draw(Test
*test
, uint32_t surface_id
, int t
)
210 draw_pos(test
, t
, &left
, &top
);
211 if ((t
% angle_parts
) == 0) {
215 if (surface_id
!= 0) {
216 color
= (color
+ 1) % 2;
223 bw
= test
->primary_width
/SINGLE_PART
;
226 bitmap
= dst
= malloc(bw
* bh
* 4);
227 //printf("allocated %p\n", dst);
229 for (i
= 0 ; i
< bh
* bw
; ++i
, dst
+=4) {
230 *dst
= (color
+i
% 255);
231 *(dst
+((1+c_i
)%3)) = 255 - color
;
232 *(dst
+((2+c_i
)%3)) = (color
* (color
+ i
)) & 0xff;
233 *(dst
+((3+c_i
)%3)) = 0;
236 bbox
.left
= left
; bbox
.top
= top
;
237 bbox
.right
= left
+ bw
; bbox
.bottom
= top
+ bh
;
238 return test_spice_create_update_from_bitmap(surface_id
, bbox
, bitmap
, 0, NULL
);
241 static SimpleSpiceUpdate
*test_spice_create_update_copy_bits(Test
*test
, uint32_t surface_id
)
243 SimpleSpiceUpdate
*update
;
244 QXLDrawable
*drawable
;
251 update
= calloc(sizeof(*update
), 1);
252 drawable
= &update
->drawable
;
254 bw
= test
->primary_width
/SINGLE_PART
;
256 bbox
.right
= bbox
.left
+ bw
;
257 bbox
.bottom
= bbox
.top
+ bh
;
258 //printf("allocated %p, %p\n", update, update->bitmap);
260 drawable
->surface_id
= surface_id
;
262 drawable
->bbox
= bbox
;
263 drawable
->clip
.type
= SPICE_CLIP_TYPE_NONE
;
264 drawable
->effect
= QXL_EFFECT_OPAQUE
;
265 simple_set_release_info(&drawable
->release_info
, (intptr_t)update
);
266 drawable
->type
= QXL_COPY_BITS
;
267 drawable
->surfaces_dest
[0] = -1;
268 drawable
->surfaces_dest
[1] = -1;
269 drawable
->surfaces_dest
[2] = -1;
271 drawable
->u
.copy_bits
.src_pos
.x
= 0;
272 drawable
->u
.copy_bits
.src_pos
.y
= 0;
274 set_cmd(&update
->ext
, QXL_CMD_DRAW
, (intptr_t)drawable
);
279 static int format_to_bpp(int format
)
282 case SPICE_SURFACE_FMT_8_A
:
284 case SPICE_SURFACE_FMT_16_555
:
285 case SPICE_SURFACE_FMT_16_565
:
287 case SPICE_SURFACE_FMT_32_xRGB
:
288 case SPICE_SURFACE_FMT_32_ARGB
:
294 static SimpleSurfaceCmd
*create_surface(int surface_id
, int format
, int width
, int height
, uint8_t *data
)
296 SimpleSurfaceCmd
*simple_cmd
= calloc(sizeof(SimpleSurfaceCmd
), 1);
297 QXLSurfaceCmd
*surface_cmd
= &simple_cmd
->surface_cmd
;
298 int bpp
= format_to_bpp(format
);
300 set_cmd(&simple_cmd
->ext
, QXL_CMD_SURFACE
, (intptr_t)surface_cmd
);
301 simple_set_release_info(&surface_cmd
->release_info
, (intptr_t)simple_cmd
);
302 surface_cmd
->type
= QXL_SURFACE_CMD_CREATE
;
303 surface_cmd
->flags
= 0; // ?
304 surface_cmd
->surface_id
= surface_id
;
305 surface_cmd
->u
.surface_create
.format
= format
;
306 surface_cmd
->u
.surface_create
.width
= width
;
307 surface_cmd
->u
.surface_create
.height
= height
;
308 surface_cmd
->u
.surface_create
.stride
= -width
* bpp
;
309 surface_cmd
->u
.surface_create
.data
= (intptr_t)data
;
313 static SimpleSurfaceCmd
*destroy_surface(int surface_id
)
315 SimpleSurfaceCmd
*simple_cmd
= calloc(sizeof(SimpleSurfaceCmd
), 1);
316 QXLSurfaceCmd
*surface_cmd
= &simple_cmd
->surface_cmd
;
318 set_cmd(&simple_cmd
->ext
, QXL_CMD_SURFACE
, (intptr_t)surface_cmd
);
319 simple_set_release_info(&surface_cmd
->release_info
, (intptr_t)simple_cmd
);
320 surface_cmd
->type
= QXL_SURFACE_CMD_DESTROY
;
321 surface_cmd
->flags
= 0; // ?
322 surface_cmd
->surface_id
= surface_id
;
326 static void create_primary_surface(Test
*test
, uint32_t width
,
329 QXLWorker
*qxl_worker
= test
->qxl_worker
;
330 QXLDevSurfaceCreate surface
= { 0, };
332 g_assert(height
<= MAX_HEIGHT
);
333 g_assert(width
<= MAX_WIDTH
);
334 g_assert(height
> 0);
337 surface
.format
= SPICE_SURFACE_FMT_32_xRGB
;
338 surface
.width
= test
->primary_width
= width
;
339 surface
.height
= test
->primary_height
= height
;
340 surface
.stride
= -width
* 4; /* negative? */
341 surface
.mouse_mode
= TRUE
; /* unused by red_worker */
343 surface
.type
= 0; /* unused by red_worker */
344 surface
.position
= 0; /* unused by red_worker */
345 surface
.mem
= (uint64_t)&test
->primary_surface
;
346 surface
.group_id
= MEM_SLOT_GROUP_ID
;
349 test
->height
= height
;
351 qxl_worker
->create_primary_surface(qxl_worker
, 0, &surface
);
354 QXLDevMemSlot slot
= {
355 .slot_group_id
= MEM_SLOT_GROUP_ID
,
364 static void attache_worker(QXLInstance
*qin
, QXLWorker
*_qxl_worker
)
366 Test
*test
= SPICE_CONTAINEROF(qin
, Test
, qxl_instance
);
368 if (test
->qxl_worker
) {
369 if (test
->qxl_worker
!= _qxl_worker
)
370 printf("%s ignored, %p is set, ignoring new %p\n", __func__
,
371 test
->qxl_worker
, _qxl_worker
);
373 printf("%s ignored, redundant\n", __func__
);
376 printf("%s\n", __func__
);
377 test
->qxl_worker
= _qxl_worker
;
378 test
->qxl_worker
->add_memslot(test
->qxl_worker
, &slot
);
379 create_primary_surface(test
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
380 test
->qxl_worker
->start(test
->qxl_worker
);
383 static void set_compression_level(QXLInstance
*qin
, int level
)
385 printf("%s\n", __func__
);
388 static void set_mm_time(QXLInstance
*qin
, uint32_t mm_time
)
392 // we now have a secondary surface
393 #define MAX_SURFACE_NUM 2
395 static void get_init_info(QXLInstance
*qin
, QXLDevInitInfo
*info
)
397 memset(info
, 0, sizeof(*info
));
398 info
->num_memslots
= 1;
399 info
->num_memslots_groups
= 1;
400 info
->memslot_id_bits
= 1;
401 info
->memslot_gen_bits
= 1;
402 info
->n_surfaces
= MAX_SURFACE_NUM
;
405 // We shall now have a ring of commands, so that we can update
406 // it from a separate thread - since get_command is called from
407 // the worker thread, and we need to sometimes do an update_area,
408 // which cannot be done from red_worker context (not via dispatcher,
409 // since you get a deadlock, and it isn't designed to be done
410 // any other way, so no point testing that).
411 int commands_end
= 0;
412 int commands_start
= 0;
413 struct QXLCommandExt
* commands
[1024];
415 #define COMMANDS_SIZE COUNT(commands)
417 static void push_command(QXLCommandExt
*ext
)
419 g_assert(commands_end
- commands_start
< COMMANDS_SIZE
);
420 commands
[commands_end
% COMMANDS_SIZE
] = ext
;
424 static struct QXLCommandExt
*get_simple_command(void)
426 struct QXLCommandExt
*ret
= commands
[commands_start
% COMMANDS_SIZE
];
427 g_assert(commands_start
< commands_end
);
432 static int get_num_commands(void)
434 return commands_end
- commands_start
;
437 // called from spice_server thread (i.e. red_worker thread)
438 static int get_command(QXLInstance
*qin
, struct QXLCommandExt
*ext
)
440 if (get_num_commands() == 0) {
443 *ext
= *get_simple_command();
447 static void produce_command(Test
*test
)
450 QXLWorker
*qxl_worker
= test
->qxl_worker
;
452 g_assert(qxl_worker
);
454 if (test
->has_secondary
)
455 test
->target_surface
= 1;
457 if (!test
->num_commands
) {
462 command
= &test
->commands
[test
->cmd_index
];
464 command
->cb(test
, command
);
466 switch (command
->command
) {
468 printf("sleep %u seconds\n", command
->sleep
.secs
);
469 sleep(command
->sleep
.secs
);
472 path_progress(&path
);
474 case SIMPLE_UPDATE
: {
477 .right
= (test
->target_surface
== 0 ? test
->primary_width
: test
->width
),
479 .bottom
= (test
->target_surface
== 0 ? test
->primary_height
: test
->height
)
481 if (rect
.right
> 0 && rect
.bottom
> 0) {
482 qxl_worker
->update_area(qxl_worker
, test
->target_surface
, &rect
, NULL
, 0, 1);
487 /* Drawing commands, they all push a command to the command ring */
488 case SIMPLE_COPY_BITS
:
489 case SIMPLE_DRAW_SOLID
:
490 case SIMPLE_DRAW_BITMAP
:
492 SimpleSpiceUpdate
*update
;
494 switch (command
->command
) {
495 case SIMPLE_COPY_BITS
:
496 update
= test_spice_create_update_copy_bits(test
, 0);
499 update
= test_spice_create_update_draw(test
, 0, path
.t
);
501 case SIMPLE_DRAW_BITMAP
:
502 update
= test_spice_create_update_from_bitmap(command
->bitmap
.surface_id
,
503 command
->bitmap
.bbox
, command
->bitmap
.bitmap
,
504 command
->bitmap
.num_clip_rects
, command
->bitmap
.clip_rects
);
506 case SIMPLE_DRAW_SOLID
:
507 update
= test_spice_create_update_solid(command
->solid
.surface_id
,
508 command
->solid
.bbox
, command
->solid
.color
);
511 push_command(&update
->ext
);
515 case SIMPLE_CREATE_SURFACE
: {
516 SimpleSurfaceCmd
*update
;
517 if (command
->create_surface
.data
) {
518 g_assert(command
->create_surface
.surface_id
> 0);
519 g_assert(command
->create_surface
.surface_id
< MAX_SURFACE_NUM
);
520 g_assert(command
->create_surface
.surface_id
== 1);
521 update
= create_surface(command
->create_surface
.surface_id
,
522 command
->create_surface
.format
,
523 command
->create_surface
.width
,
524 command
->create_surface
.height
,
525 command
->create_surface
.data
);
527 update
= create_surface(test
->target_surface
, SPICE_SURFACE_FMT_32_xRGB
,
528 SURF_WIDTH
, SURF_HEIGHT
,
529 test
->secondary_surface
);
531 push_command(&update
->ext
);
532 test
->has_secondary
= 1;
536 case SIMPLE_DESTROY_SURFACE
: {
537 SimpleSurfaceCmd
*update
;
538 test
->has_secondary
= 0;
539 update
= destroy_surface(test
->target_surface
);
540 test
->target_surface
= 0;
541 push_command(&update
->ext
);
545 case DESTROY_PRIMARY
:
546 qxl_worker
->destroy_primary_surface(qxl_worker
, 0);
550 create_primary_surface(test
,
551 command
->create_primary
.width
, command
->create_primary
.height
);
554 test
->cmd_index
= (test
->cmd_index
+ 1) % test
->num_commands
;
557 static int req_cmd_notification(QXLInstance
*qin
)
559 Test
*test
= SPICE_CONTAINEROF(qin
, Test
, qxl_instance
);
561 test
->core
->timer_start(test
->wakeup_timer
, test
->wakeup_ms
);
565 static void do_wakeup(void *opaque
)
570 test
->cursor_notify
= NOTIFY_CURSOR_BATCH
;
571 for (notify
= NOTIFY_DISPLAY_BATCH
; notify
> 0;--notify
) {
572 produce_command(test
);
575 test
->core
->timer_start(test
->wakeup_timer
, test
->wakeup_ms
);
576 test
->qxl_worker
->wakeup(test
->qxl_worker
);
579 static void release_resource(QXLInstance
*qin
, struct QXLReleaseInfoExt release_info
)
581 QXLCommandExt
*ext
= (QXLCommandExt
*)(unsigned long)release_info
.info
->id
;
582 //printf("%s\n", __func__);
583 g_assert(release_info
.group_id
== MEM_SLOT_GROUP_ID
);
584 switch (ext
->cmd
.type
) {
586 test_spice_destroy_update((void*)ext
);
588 case QXL_CMD_SURFACE
:
591 case QXL_CMD_CURSOR
: {
592 QXLCursorCmd
*cmd
= (QXLCursorCmd
*)(unsigned long)ext
->cmd
.data
;
593 if (cmd
->type
== QXL_CURSOR_SET
) {
604 #define CURSOR_WIDTH 32
605 #define CURSOR_HEIGHT 32
609 uint8_t data
[CURSOR_WIDTH
* CURSOR_HEIGHT
* 4]; // 32bit per pixel
612 static void cursor_init()
614 cursor
.cursor
.header
.unique
= 0;
615 cursor
.cursor
.header
.type
= SPICE_CURSOR_TYPE_COLOR32
;
616 cursor
.cursor
.header
.width
= CURSOR_WIDTH
;
617 cursor
.cursor
.header
.height
= CURSOR_HEIGHT
;
618 cursor
.cursor
.header
.hot_spot_x
= 0;
619 cursor
.cursor
.header
.hot_spot_y
= 0;
620 cursor
.cursor
.data_size
= CURSOR_WIDTH
* CURSOR_HEIGHT
* 4;
622 // X drivers addes it to the cursor size because it could be
623 // cursor data information or another cursor related stuffs.
624 // Otherwise, the code will break in client/cursor.cpp side,
625 // that expect the data_size plus cursor information.
626 // Blame cursor protocol for this. :-)
627 cursor
.cursor
.data_size
+= 128;
628 cursor
.cursor
.chunk
.data_size
= cursor
.cursor
.data_size
;
629 cursor
.cursor
.chunk
.prev_chunk
= cursor
.cursor
.chunk
.next_chunk
= 0;
632 static int get_cursor_command(QXLInstance
*qin
, struct QXLCommandExt
*ext
)
634 Test
*test
= SPICE_CONTAINEROF(qin
, Test
, qxl_instance
);
635 static int color
= 0;
637 static int x
= 0, y
= 0;
638 QXLCursorCmd
*cursor_cmd
;
641 if (!test
->cursor_notify
) {
645 test
->cursor_notify
--;
646 cmd
= calloc(sizeof(QXLCommandExt
), 1);
647 cursor_cmd
= calloc(sizeof(QXLCursorCmd
), 1);
649 cursor_cmd
->release_info
.id
= (unsigned long)cmd
;
652 cursor_cmd
->type
= QXL_CURSOR_SET
;
653 cursor_cmd
->u
.set
.position
.x
= 0;
654 cursor_cmd
->u
.set
.position
.y
= 0;
655 cursor_cmd
->u
.set
.visible
= TRUE
;
656 cursor_cmd
->u
.set
.shape
= (unsigned long)&cursor
;
657 // Only a white rect (32x32) as cursor
658 memset(cursor
.data
, 255, sizeof(cursor
.data
));
661 cursor_cmd
->type
= QXL_CURSOR_MOVE
;
662 cursor_cmd
->u
.position
.x
= x
++ % test
->primary_width
;
663 cursor_cmd
->u
.position
.y
= y
++ % test
->primary_height
;
666 cmd
->cmd
.data
= (unsigned long)cursor_cmd
;
667 cmd
->cmd
.type
= QXL_CMD_CURSOR
;
668 cmd
->group_id
= MEM_SLOT_GROUP_ID
;
671 //printf("%s\n", __func__);
675 static int req_cursor_notification(QXLInstance
*qin
)
677 printf("%s\n", __func__
);
681 static void notify_update(QXLInstance
*qin
, uint32_t update_id
)
683 printf("%s\n", __func__
);
686 static int flush_resources(QXLInstance
*qin
)
688 printf("%s\n", __func__
);
692 static int client_monitors_config(QXLInstance
*qin
,
693 VDAgentMonitorsConfig
*monitors_config
)
695 if (!monitors_config
) {
696 printf("%s: NULL monitors_config\n", __func__
);
698 printf("%s: %d\n", __func__
, monitors_config
->num_of_monitors
);
703 static void set_client_capabilities(QXLInstance
*qin
,
704 uint8_t client_present
,
707 Test
*test
= SPICE_CONTAINEROF(qin
, Test
, qxl_instance
);
709 printf("%s: present %d caps %d\n", __func__
, client_present
, caps
[0]);
710 if (test
->on_client_connected
&& client_present
) {
711 test
->on_client_connected(test
);
713 if (test
->on_client_disconnected
&& !client_present
) {
714 test
->on_client_disconnected(test
);
718 QXLInterface display_sif
= {
720 .type
= SPICE_INTERFACE_QXL
,
721 .description
= "test",
722 .major_version
= SPICE_INTERFACE_QXL_MAJOR
,
723 .minor_version
= SPICE_INTERFACE_QXL_MINOR
725 .attache_worker
= attache_worker
,
726 .set_compression_level
= set_compression_level
,
727 .set_mm_time
= set_mm_time
,
728 .get_init_info
= get_init_info
,
730 /* the callbacks below are called from spice server thread context */
731 .get_command
= get_command
,
732 .req_cmd_notification
= req_cmd_notification
,
733 .release_resource
= release_resource
,
734 .get_cursor_command
= get_cursor_command
,
735 .req_cursor_notification
= req_cursor_notification
,
736 .notify_update
= notify_update
,
737 .flush_resources
= flush_resources
,
738 .client_monitors_config
= client_monitors_config
,
739 .set_client_capabilities
= set_client_capabilities
,
742 /* interface for tests */
743 void test_add_display_interface(Test
* test
)
745 spice_server_add_interface(test
->server
, &test
->qxl_instance
.base
);
748 static int vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
750 printf("%s: %d\n", __func__
, len
);
754 static int vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
756 printf("%s: %d\n", __func__
, len
);
760 static void vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
762 printf("%s: %d\n", __func__
, connected
);
765 static SpiceCharDeviceInterface vdagent_sif
= {
766 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
767 .base
.description
= "test spice virtual channel char device",
768 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
769 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
775 SpiceCharDeviceInstance vdagent_sin
= {
777 .sif
= &vdagent_sif
.base
,
779 .subtype
= "vdagent",
782 void test_add_agent_interface(SpiceServer
*server
)
784 spice_server_add_interface(server
, &vdagent_sin
.base
);
787 void test_set_simple_command_list(Test
*test
, int *simple_commands
, int num_commands
)
792 test
->commands
= malloc(sizeof(*test
->commands
) * num_commands
);
793 memset(test
->commands
, 0, sizeof(*test
->commands
) * num_commands
);
794 test
->num_commands
= num_commands
;
795 for (i
= 0 ; i
< num_commands
; ++i
) {
796 test
->commands
[i
].command
= simple_commands
[i
];
800 void test_set_command_list(Test
*test
, Command
*commands
, int num_commands
)
802 test
->commands
= commands
;
803 test
->num_commands
= num_commands
;
807 Test
*test_new(SpiceCoreInterface
*core
)
810 Test
*test
= g_new0(Test
, 1);
811 SpiceServer
* server
= spice_server_new();
813 test
->qxl_instance
.base
.sif
= &display_sif
.base
;
814 test
->qxl_instance
.id
= 0;
817 test
->server
= server
;
818 test
->wakeup_ms
= 50;
819 test
->cursor_notify
= NOTIFY_CURSOR_BATCH
;
820 // some common initialization for all display tests
821 printf("TESTER: listening on port %d (unsecure)\n", port
);
822 spice_server_set_port(server
, port
);
823 spice_server_set_noauth(server
);
824 int res
= spice_server_init(server
, core
);
826 g_error("spice_server_init failed, res = %d\n", res
);
830 path_init(&path
, 0, angle_parts
);
831 test
->has_secondary
= 0;
832 test
->wakeup_timer
= core
->timer_add(do_wakeup
, test
);
837 __attribute__((noreturn
))
838 void usage(const char *argv0
, const int exitcode
)
841 printf("usage: %s\n", argv0
);
845 void spice_test_config_parse_args(int argc
, char **argv
)
847 struct option options
[] = {
848 // {"automated-tests", no_argument, &has_automated_tests, 1},
854 while ((val
= getopt_long(argc
, argv
, "", options
, &option_index
)) != -1) {
857 printf("unrecognized option '%s'\n", argv
[optind
- 1]);
858 usage(argv
[0], EXIT_FAILURE
);
865 printf("unknown argument '%s'\n", argv
[optind
]);
866 usage(argv
[0], EXIT_FAILURE
);