1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 *
7 * TODO:
8 *
9 * - Enable SSL
10 * - Manage SetOptions/ResetOptions commands
11 */
12
13 #include "qemu/osdep.h"
14 #include "system/system.h"
15 #include "qemu/main-loop.h"
16 #include "qemu/sockets.h"
17 #include "qapi/error.h"
18 #include "qom/object_interfaces.h"
19 #include "io/channel-socket.h"
20 #include "ui/input.h"
21 #include "qom/object.h"
22 #include "ui/vnc_keysym.h" /* use name2keysym from VNC as we use X11 values */
23 #include "qemu/cutils.h"
24 #include "qapi/qmp/qerror.h"
25 #include "input-barrier.h"
26
27 #define TYPE_INPUT_BARRIER "input-barrier"
28 OBJECT_DECLARE_SIMPLE_TYPE(InputBarrier,
29 INPUT_BARRIER)
30
31
32 #define MAX_HELLO_LENGTH 1024
33
34 struct InputBarrier {
35 Object parent;
36
37 QIOChannelSocket *sioc;
38 guint ioc_tag;
39
40 /* display properties */
41 gchar *name;
42 int16_t x_origin, y_origin;
43 int16_t width, height;
44
45 /* keyboard/mouse server */
46
47 SocketAddress saddr;
48
49 char buffer[MAX_HELLO_LENGTH];
50 };
51
52
53 static const char *cmd_names[] = {
54 [barrierCmdCNoop] = "CNOP",
55 [barrierCmdCClose] = "CBYE",
56 [barrierCmdCEnter] = "CINN",
57 [barrierCmdCLeave] = "COUT",
58 [barrierCmdCClipboard] = "CCLP",
59 [barrierCmdCScreenSaver] = "CSEC",
60 [barrierCmdCResetOptions] = "CROP",
61 [barrierCmdCInfoAck] = "CIAK",
62 [barrierCmdCKeepAlive] = "CALV",
63 [barrierCmdDKeyDown] = "DKDN",
64 [barrierCmdDKeyRepeat] = "DKRP",
65 [barrierCmdDKeyUp] = "DKUP",
66 [barrierCmdDMouseDown] = "DMDN",
67 [barrierCmdDMouseUp] = "DMUP",
68 [barrierCmdDMouseMove] = "DMMV",
69 [barrierCmdDMouseRelMove] = "DMRM",
70 [barrierCmdDMouseWheel] = "DMWM",
71 [barrierCmdDClipboard] = "DCLP",
72 [barrierCmdDInfo] = "DINF",
73 [barrierCmdDSetOptions] = "DSOP",
74 [barrierCmdDFileTransfer] = "DFTR",
75 [barrierCmdDDragInfo] = "DDRG",
76 [barrierCmdQInfo] = "QINF",
77 [barrierCmdEIncompatible] = "EICV",
78 [barrierCmdEBusy] = "EBSY",
79 [barrierCmdEUnknown] = "EUNK",
80 [barrierCmdEBad] = "EBAD",
81 [barrierCmdHello] = "Barrier",
82 [barrierCmdHelloBack] = "Barrier",
83 };
84
85 static kbd_layout_t *kbd_layout;
86
input_barrier_to_qcode(uint16_t keyid,uint16_t keycode)87 static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode)
88 {
89 /* keycode is optional, if it is not provided use keyid */
90 if (keycode && keycode <= qemu_input_map_xorgkbd_to_qcode_len) {
91 return qemu_input_map_xorgkbd_to_qcode[keycode];
92 }
93
94 if (keyid >= 0xE000 && keyid <= 0xEFFF) {
95 keyid += 0x1000;
96 }
97
98 /* keyid is the X11 key id */
99 if (kbd_layout) {
100 keycode = keysym2scancode(kbd_layout, keyid, NULL, false);
101
102 return qemu_input_key_number_to_qcode(keycode);
103 }
104
105 return qemu_input_map_x11_to_qcode[keyid];
106 }
107
input_barrier_to_mouse(uint8_t buttonid)108 static int input_barrier_to_mouse(uint8_t buttonid)
109 {
110 switch (buttonid) {
111 case barrierButtonLeft:
112 return INPUT_BUTTON_LEFT;
113 case barrierButtonMiddle:
114 return INPUT_BUTTON_MIDDLE;
115 case barrierButtonRight:
116 return INPUT_BUTTON_RIGHT;
117 case barrierButtonExtra0:
118 return INPUT_BUTTON_SIDE;
119 }
120 return buttonid;
121 }
122
123 #define read_char(x, p, l) \
124 do { \
125 int size = sizeof(char); \
126 if (l < size) { \
127 return G_SOURCE_REMOVE; \
128 } \
129 x = *(char *)p; \
130 p += size; \
131 l -= size; \
132 } while (0)
133
134 #define read_short(x, p, l) \
135 do { \
136 int size = sizeof(short); \
137 if (l < size) { \
138 return G_SOURCE_REMOVE; \
139 } \
140 x = ntohs(*(short *)p); \
141 p += size; \
142 l -= size; \
143 } while (0)
144
145 #define write_short(p, x, l) \
146 do { \
147 int size = sizeof(short); \
148 if (l < size) { \
149 return G_SOURCE_REMOVE; \
150 } \
151 *(short *)p = htons(x); \
152 p += size; \
153 l -= size; \
154 } while (0)
155
156 #define read_int(x, p, l) \
157 do { \
158 int size = sizeof(int); \
159 if (l < size) { \
160 return G_SOURCE_REMOVE; \
161 } \
162 x = ntohl(*(int *)p); \
163 p += size; \
164 l -= size; \
165 } while (0)
166
167 #define write_int(p, x, l) \
168 do { \
169 int size = sizeof(int); \
170 if (l < size) { \
171 return G_SOURCE_REMOVE; \
172 } \
173 *(int *)p = htonl(x); \
174 p += size; \
175 l -= size; \
176 } while (0)
177
178 #define write_cmd(p, c, l) \
179 do { \
180 int size = strlen(cmd_names[c]); \
181 if (l < size) { \
182 return G_SOURCE_REMOVE; \
183 } \
184 memcpy(p, cmd_names[c], size); \
185 p += size; \
186 l -= size; \
187 } while (0)
188
189 #define write_string(p, s, l) \
190 do { \
191 int size = strlen(s); \
192 if (l < size + sizeof(int)) { \
193 return G_SOURCE_REMOVE; \
194 } \
195 *(int *)p = htonl(size); \
196 p += sizeof(size); \
197 l -= sizeof(size); \
198 memcpy(p, s, size); \
199 p += size; \
200 l -= size; \
201 } while (0)
202
readcmd(InputBarrier * ib,struct barrierMsg * msg)203 static gboolean readcmd(InputBarrier *ib, struct barrierMsg *msg)
204 {
205 int ret, len, i;
206 enum barrierCmd cmd;
207 char *p;
208
209 ret = qio_channel_read(QIO_CHANNEL(ib->sioc), (char *)&len, sizeof(len),
210 NULL);
211 if (ret < 0) {
212 return G_SOURCE_REMOVE;
213 }
214
215 len = ntohl(len);
216 if (len > MAX_HELLO_LENGTH) {
217 return G_SOURCE_REMOVE;
218 }
219
220 ret = qio_channel_read(QIO_CHANNEL(ib->sioc), ib->buffer, len, NULL);
221 if (ret < 0) {
222 return G_SOURCE_REMOVE;
223 }
224
225 p = ib->buffer;
226 if (len >= strlen(cmd_names[barrierCmdHello]) &&
227 memcmp(p, cmd_names[barrierCmdHello],
228 strlen(cmd_names[barrierCmdHello])) == 0) {
229 cmd = barrierCmdHello;
230 p += strlen(cmd_names[barrierCmdHello]);
231 len -= strlen(cmd_names[barrierCmdHello]);
232 } else {
233 for (cmd = 0; cmd < barrierCmdHello; cmd++) {
234 if (memcmp(ib->buffer, cmd_names[cmd], 4) == 0) {
235 break;
236 }
237 }
238
239 if (cmd == barrierCmdHello) {
240 return G_SOURCE_REMOVE;
241 }
242 p += 4;
243 len -= 4;
244 }
245
246 msg->cmd = cmd;
247 switch (cmd) {
248 /* connection */
249 case barrierCmdHello:
250 read_short(msg->version.major, p, len);
251 read_short(msg->version.minor, p, len);
252 break;
253 case barrierCmdDSetOptions:
254 read_int(msg->set.nb, p, len);
255 msg->set.nb /= 2;
256 if (msg->set.nb > BARRIER_MAX_OPTIONS) {
257 msg->set.nb = BARRIER_MAX_OPTIONS;
258 }
259 i = 0;
260 while (len && i < msg->set.nb) {
261 read_int(msg->set.option[i].id, p, len);
262 /* it's a string, restore endianness */
263 msg->set.option[i].id = htonl(msg->set.option[i].id);
264 msg->set.option[i].nul = 0;
265 read_int(msg->set.option[i].value, p, len);
266 i++;
267 }
268 break;
269 case barrierCmdQInfo:
270 break;
271
272 /* mouse */
273 case barrierCmdDMouseMove:
274 case barrierCmdDMouseRelMove:
275 read_short(msg->mousepos.x, p, len);
276 read_short(msg->mousepos.y, p, len);
277 break;
278 case barrierCmdDMouseDown:
279 case barrierCmdDMouseUp:
280 read_char(msg->mousebutton.buttonid, p, len);
281 break;
282 case barrierCmdDMouseWheel:
283 read_short(msg->mousepos.y, p, len);
284 msg->mousepos.x = 0;
285 if (len) {
286 msg->mousepos.x = msg->mousepos.y;
287 read_short(msg->mousepos.y, p, len);
288 }
289 break;
290
291 /* keyboard */
292 case barrierCmdDKeyDown:
293 case barrierCmdDKeyUp:
294 read_short(msg->key.keyid, p, len);
295 read_short(msg->key.modifier, p, len);
296 msg->key.button = 0;
297 if (len) {
298 read_short(msg->key.button, p, len);
299 }
300 break;
301 case barrierCmdDKeyRepeat:
302 read_short(msg->repeat.keyid, p, len);
303 read_short(msg->repeat.modifier, p, len);
304 read_short(msg->repeat.repeat, p, len);
305 msg->repeat.button = 0;
306 if (len) {
307 read_short(msg->repeat.button, p, len);
308 }
309 break;
310 case barrierCmdCInfoAck:
311 case barrierCmdCResetOptions:
312 case barrierCmdCEnter:
313 case barrierCmdDClipboard:
314 case barrierCmdCKeepAlive:
315 case barrierCmdCLeave:
316 case barrierCmdCClose:
317 break;
318
319 /* Invalid from the server */
320 case barrierCmdHelloBack:
321 case barrierCmdCNoop:
322 case barrierCmdDInfo:
323 break;
324
325 /* Error codes */
326 case barrierCmdEIncompatible:
327 read_short(msg->version.major, p, len);
328 read_short(msg->version.minor, p, len);
329 break;
330 case barrierCmdEBusy:
331 case barrierCmdEUnknown:
332 case barrierCmdEBad:
333 break;
334 default:
335 return G_SOURCE_REMOVE;
336 }
337
338 return G_SOURCE_CONTINUE;
339 }
340
writecmd(InputBarrier * ib,struct barrierMsg * msg)341 static gboolean writecmd(InputBarrier *ib, struct barrierMsg *msg)
342 {
343 char *p;
344 int ret, i;
345 int avail, len;
346
347 p = ib->buffer;
348 avail = MAX_HELLO_LENGTH;
349
350 /* reserve space to store the length */
351 p += sizeof(int);
352 avail -= sizeof(int);
353
354 switch (msg->cmd) {
355 case barrierCmdHello:
356 if (msg->version.major < BARRIER_VERSION_MAJOR ||
357 (msg->version.major == BARRIER_VERSION_MAJOR &&
358 msg->version.minor < BARRIER_VERSION_MINOR)) {
359 ib->ioc_tag = 0;
360 return G_SOURCE_REMOVE;
361 }
362 write_cmd(p, barrierCmdHelloBack, avail);
363 write_short(p, BARRIER_VERSION_MAJOR, avail);
364 write_short(p, BARRIER_VERSION_MINOR, avail);
365 write_string(p, ib->name, avail);
366 break;
367 case barrierCmdCClose:
368 ib->ioc_tag = 0;
369 return G_SOURCE_REMOVE;
370 case barrierCmdQInfo:
371 write_cmd(p, barrierCmdDInfo, avail);
372 write_short(p, ib->x_origin, avail);
373 write_short(p, ib->y_origin, avail);
374 write_short(p, ib->width, avail);
375 write_short(p, ib->height, avail);
376 write_short(p, 0, avail); /* warpsize (obsolete) */
377 write_short(p, 0, avail); /* mouse x */
378 write_short(p, 0, avail); /* mouse y */
379 break;
380 case barrierCmdCInfoAck:
381 break;
382 case barrierCmdCResetOptions:
383 /* TODO: reset options */
384 break;
385 case barrierCmdDSetOptions:
386 /* TODO: set options */
387 break;
388 case barrierCmdCEnter:
389 break;
390 case barrierCmdDClipboard:
391 break;
392 case barrierCmdCKeepAlive:
393 write_cmd(p, barrierCmdCKeepAlive, avail);
394 break;
395 case barrierCmdCLeave:
396 break;
397
398 /* mouse */
399 case barrierCmdDMouseMove:
400 qemu_input_queue_abs(NULL, INPUT_AXIS_X, msg->mousepos.x,
401 ib->x_origin, ib->width);
402 qemu_input_queue_abs(NULL, INPUT_AXIS_Y, msg->mousepos.y,
403 ib->y_origin, ib->height);
404 qemu_input_event_sync();
405 break;
406 case barrierCmdDMouseRelMove:
407 qemu_input_queue_rel(NULL, INPUT_AXIS_X, msg->mousepos.x);
408 qemu_input_queue_rel(NULL, INPUT_AXIS_Y, msg->mousepos.y);
409 qemu_input_event_sync();
410 break;
411 case barrierCmdDMouseDown:
412 qemu_input_queue_btn(NULL,
413 input_barrier_to_mouse(msg->mousebutton.buttonid),
414 true);
415 qemu_input_event_sync();
416 break;
417 case barrierCmdDMouseUp:
418 qemu_input_queue_btn(NULL,
419 input_barrier_to_mouse(msg->mousebutton.buttonid),
420 false);
421 qemu_input_event_sync();
422 break;
423 case barrierCmdDMouseWheel:
424 qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
425 : INPUT_BUTTON_WHEEL_DOWN, true);
426 qemu_input_event_sync();
427 qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
428 : INPUT_BUTTON_WHEEL_DOWN, false);
429 qemu_input_event_sync();
430 break;
431
432 /* keyboard */
433 case barrierCmdDKeyDown:
434 qemu_input_event_send_key_qcode(NULL,
435 input_barrier_to_qcode(msg->key.keyid, msg->key.button),
436 true);
437 break;
438 case barrierCmdDKeyRepeat:
439 for (i = 0; i < msg->repeat.repeat; i++) {
440 qemu_input_event_send_key_qcode(NULL,
441 input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
442 false);
443 qemu_input_event_send_key_qcode(NULL,
444 input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
445 true);
446 }
447 break;
448 case barrierCmdDKeyUp:
449 qemu_input_event_send_key_qcode(NULL,
450 input_barrier_to_qcode(msg->key.keyid, msg->key.button),
451 false);
452 break;
453 default:
454 write_cmd(p, barrierCmdEUnknown, avail);
455 break;
456 }
457
458 len = MAX_HELLO_LENGTH - avail - sizeof(int);
459 if (len) {
460 p = ib->buffer;
461 avail = sizeof(len);
462 write_int(p, len, avail);
463 ret = qio_channel_write(QIO_CHANNEL(ib->sioc), ib->buffer,
464 len + sizeof(len), NULL);
465 if (ret < 0) {
466 ib->ioc_tag = 0;
467 return G_SOURCE_REMOVE;
468 }
469 }
470
471 return G_SOURCE_CONTINUE;
472 }
473
input_barrier_event(QIOChannel * ioc G_GNUC_UNUSED,GIOCondition condition,void * opaque)474 static gboolean input_barrier_event(QIOChannel *ioc G_GNUC_UNUSED,
475 GIOCondition condition, void *opaque)
476 {
477 InputBarrier *ib = opaque;
478 int ret;
479 struct barrierMsg msg;
480
481 ret = readcmd(ib, &msg);
482 if (ret == G_SOURCE_REMOVE) {
483 ib->ioc_tag = 0;
484 return G_SOURCE_REMOVE;
485 }
486
487 return writecmd(ib, &msg);
488 }
489
input_barrier_complete(UserCreatable * uc,Error ** errp)490 static void input_barrier_complete(UserCreatable *uc, Error **errp)
491 {
492 InputBarrier *ib = INPUT_BARRIER(uc);
493
494 if (!ib->name) {
495 error_setg(errp, QERR_MISSING_PARAMETER, "name");
496 return;
497 }
498
499 /*
500 * Connect to the primary
501 * Primary is the server where the keyboard and the mouse
502 * are connected and forwarded to the secondary (the client)
503 */
504
505 ib->sioc = qio_channel_socket_new();
506 qio_channel_set_name(QIO_CHANNEL(ib->sioc), "barrier-client");
507
508 if (qio_channel_socket_connect_sync(ib->sioc, &ib->saddr, errp) < 0) {
509 return;
510 }
511
512 qio_channel_set_delay(QIO_CHANNEL(ib->sioc), false);
513
514 ib->ioc_tag = qio_channel_add_watch(QIO_CHANNEL(ib->sioc), G_IO_IN,
515 input_barrier_event, ib, NULL);
516 }
517
input_barrier_instance_finalize(Object * obj)518 static void input_barrier_instance_finalize(Object *obj)
519 {
520 InputBarrier *ib = INPUT_BARRIER(obj);
521
522 if (ib->ioc_tag) {
523 g_source_remove(ib->ioc_tag);
524 ib->ioc_tag = 0;
525 }
526
527 if (ib->sioc) {
528 qio_channel_close(QIO_CHANNEL(ib->sioc), NULL);
529 object_unref(OBJECT(ib->sioc));
530 }
531 g_free(ib->name);
532 g_free(ib->saddr.u.inet.host);
533 g_free(ib->saddr.u.inet.port);
534 }
535
input_barrier_get_name(Object * obj,Error ** errp)536 static char *input_barrier_get_name(Object *obj, Error **errp)
537 {
538 InputBarrier *ib = INPUT_BARRIER(obj);
539
540 return g_strdup(ib->name);
541 }
542
input_barrier_set_name(Object * obj,const char * value,Error ** errp)543 static void input_barrier_set_name(Object *obj, const char *value,
544 Error **errp)
545 {
546 InputBarrier *ib = INPUT_BARRIER(obj);
547
548 if (ib->name) {
549 error_setg(errp, "name property already set");
550 return;
551 }
552 ib->name = g_strdup(value);
553 }
554
input_barrier_get_server(Object * obj,Error ** errp)555 static char *input_barrier_get_server(Object *obj, Error **errp)
556 {
557 InputBarrier *ib = INPUT_BARRIER(obj);
558
559 return g_strdup(ib->saddr.u.inet.host);
560 }
561
input_barrier_set_server(Object * obj,const char * value,Error ** errp)562 static void input_barrier_set_server(Object *obj, const char *value,
563 Error **errp)
564 {
565 InputBarrier *ib = INPUT_BARRIER(obj);
566
567 g_free(ib->saddr.u.inet.host);
568 ib->saddr.u.inet.host = g_strdup(value);
569 }
570
input_barrier_get_port(Object * obj,Error ** errp)571 static char *input_barrier_get_port(Object *obj, Error **errp)
572 {
573 InputBarrier *ib = INPUT_BARRIER(obj);
574
575 return g_strdup(ib->saddr.u.inet.port);
576 }
577
input_barrier_set_port(Object * obj,const char * value,Error ** errp)578 static void input_barrier_set_port(Object *obj, const char *value,
579 Error **errp)
580 {
581 InputBarrier *ib = INPUT_BARRIER(obj);
582
583 g_free(ib->saddr.u.inet.port);
584 ib->saddr.u.inet.port = g_strdup(value);
585 }
586
input_barrier_set_x_origin(Object * obj,const char * value,Error ** errp)587 static void input_barrier_set_x_origin(Object *obj, const char *value,
588 Error **errp)
589 {
590 InputBarrier *ib = INPUT_BARRIER(obj);
591 int result, err;
592
593 err = qemu_strtoi(value, NULL, 0, &result);
594 if (err < 0 || result < 0 || result > SHRT_MAX) {
595 error_setg(errp,
596 "x-origin property must be in the range [0..%d]", SHRT_MAX);
597 return;
598 }
599 ib->x_origin = result;
600 }
601
input_barrier_get_x_origin(Object * obj,Error ** errp)602 static char *input_barrier_get_x_origin(Object *obj, Error **errp)
603 {
604 InputBarrier *ib = INPUT_BARRIER(obj);
605
606 return g_strdup_printf("%d", ib->x_origin);
607 }
608
input_barrier_set_y_origin(Object * obj,const char * value,Error ** errp)609 static void input_barrier_set_y_origin(Object *obj, const char *value,
610 Error **errp)
611 {
612 InputBarrier *ib = INPUT_BARRIER(obj);
613 int result, err;
614
615 err = qemu_strtoi(value, NULL, 0, &result);
616 if (err < 0 || result < 0 || result > SHRT_MAX) {
617 error_setg(errp,
618 "y-origin property must be in the range [0..%d]", SHRT_MAX);
619 return;
620 }
621 ib->y_origin = result;
622 }
623
input_barrier_get_y_origin(Object * obj,Error ** errp)624 static char *input_barrier_get_y_origin(Object *obj, Error **errp)
625 {
626 InputBarrier *ib = INPUT_BARRIER(obj);
627
628 return g_strdup_printf("%d", ib->y_origin);
629 }
630
input_barrier_set_width(Object * obj,const char * value,Error ** errp)631 static void input_barrier_set_width(Object *obj, const char *value,
632 Error **errp)
633 {
634 InputBarrier *ib = INPUT_BARRIER(obj);
635 int result, err;
636
637 err = qemu_strtoi(value, NULL, 0, &result);
638 if (err < 0 || result < 0 || result > SHRT_MAX) {
639 error_setg(errp,
640 "width property must be in the range [0..%d]", SHRT_MAX);
641 return;
642 }
643 ib->width = result;
644 }
645
input_barrier_get_width(Object * obj,Error ** errp)646 static char *input_barrier_get_width(Object *obj, Error **errp)
647 {
648 InputBarrier *ib = INPUT_BARRIER(obj);
649
650 return g_strdup_printf("%d", ib->width);
651 }
652
input_barrier_set_height(Object * obj,const char * value,Error ** errp)653 static void input_barrier_set_height(Object *obj, const char *value,
654 Error **errp)
655 {
656 InputBarrier *ib = INPUT_BARRIER(obj);
657 int result, err;
658
659 err = qemu_strtoi(value, NULL, 0, &result);
660 if (err < 0 || result < 0 || result > SHRT_MAX) {
661 error_setg(errp,
662 "height property must be in the range [0..%d]", SHRT_MAX);
663 return;
664 }
665 ib->height = result;
666 }
667
input_barrier_get_height(Object * obj,Error ** errp)668 static char *input_barrier_get_height(Object *obj, Error **errp)
669 {
670 InputBarrier *ib = INPUT_BARRIER(obj);
671
672 return g_strdup_printf("%d", ib->height);
673 }
674
input_barrier_instance_init(Object * obj)675 static void input_barrier_instance_init(Object *obj)
676 {
677 InputBarrier *ib = INPUT_BARRIER(obj);
678
679 /* always use generic keymaps */
680 if (keyboard_layout && !kbd_layout) {
681 /* We use X11 key id, so use VNC name2keysym */
682 kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
683 &error_fatal);
684 }
685
686 ib->saddr.type = SOCKET_ADDRESS_TYPE_INET;
687 ib->saddr.u.inet.host = g_strdup("localhost");
688 ib->saddr.u.inet.port = g_strdup("24800");
689
690 ib->x_origin = 0;
691 ib->y_origin = 0;
692 ib->width = 1920;
693 ib->height = 1080;
694 }
695
input_barrier_class_init(ObjectClass * oc,const void * data)696 static void input_barrier_class_init(ObjectClass *oc, const void *data)
697 {
698 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
699
700 ucc->complete = input_barrier_complete;
701
702 object_class_property_add_str(oc, "name",
703 input_barrier_get_name,
704 input_barrier_set_name);
705 object_class_property_add_str(oc, "server",
706 input_barrier_get_server,
707 input_barrier_set_server);
708 object_class_property_add_str(oc, "port",
709 input_barrier_get_port,
710 input_barrier_set_port);
711 object_class_property_add_str(oc, "x-origin",
712 input_barrier_get_x_origin,
713 input_barrier_set_x_origin);
714 object_class_property_add_str(oc, "y-origin",
715 input_barrier_get_y_origin,
716 input_barrier_set_y_origin);
717 object_class_property_add_str(oc, "width",
718 input_barrier_get_width,
719 input_barrier_set_width);
720 object_class_property_add_str(oc, "height",
721 input_barrier_get_height,
722 input_barrier_set_height);
723 }
724
725 static const TypeInfo input_barrier_info = {
726 .name = TYPE_INPUT_BARRIER,
727 .parent = TYPE_OBJECT,
728 .class_init = input_barrier_class_init,
729 .instance_size = sizeof(InputBarrier),
730 .instance_init = input_barrier_instance_init,
731 .instance_finalize = input_barrier_instance_finalize,
732 .interfaces = (const InterfaceInfo[]) {
733 { TYPE_USER_CREATABLE },
734 { }
735 }
736 };
737
register_types(void)738 static void register_types(void)
739 {
740 type_register_static(&input_barrier_info);
741 }
742
743 type_init(register_types);
744