xref: /openbmc/qemu/ui/input-barrier.c (revision 2dd52baff298ca02ca7e75934a97616ae38aafea)
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