xref: /qemu/ui/input-barrier.c (revision 399a0477)
16105683dSLaurent Vivier /*
26105683dSLaurent Vivier  * SPDX-License-Identifier: GPL-2.0-or-later
36105683dSLaurent Vivier  *
46105683dSLaurent Vivier  * This work is licensed under the terms of the GNU GPL, version 2 or later.
56105683dSLaurent Vivier  * See the COPYING file in the top-level directory.
6*399a0477SPeter Maydell  *
7*399a0477SPeter Maydell  * TODO:
8*399a0477SPeter Maydell  *
9*399a0477SPeter Maydell  *  - Enable SSL
10*399a0477SPeter Maydell  *  - Manage SetOptions/ResetOptions commands
116105683dSLaurent Vivier  */
126105683dSLaurent Vivier 
136105683dSLaurent Vivier #include "qemu/osdep.h"
146105683dSLaurent Vivier #include "sysemu/sysemu.h"
156105683dSLaurent Vivier #include "qemu/main-loop.h"
166105683dSLaurent Vivier #include "qemu/sockets.h"
176105683dSLaurent Vivier #include "qapi/error.h"
186105683dSLaurent Vivier #include "qom/object_interfaces.h"
196105683dSLaurent Vivier #include "io/channel-socket.h"
206105683dSLaurent Vivier #include "ui/input.h"
21db1015e9SEduardo Habkost #include "qom/object.h"
226105683dSLaurent Vivier #include "ui/vnc_keysym.h" /* use name2keysym from VNC as we use X11 values */
236105683dSLaurent Vivier #include "qemu/cutils.h"
246105683dSLaurent Vivier #include "qapi/qmp/qerror.h"
256105683dSLaurent Vivier #include "input-barrier.h"
266105683dSLaurent Vivier 
276105683dSLaurent Vivier #define TYPE_INPUT_BARRIER "input-barrier"
2830b5707cSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(InputBarrier,
29c734cd40SEduardo Habkost                            INPUT_BARRIER)
306105683dSLaurent Vivier 
316105683dSLaurent Vivier 
326105683dSLaurent Vivier #define MAX_HELLO_LENGTH 1024
336105683dSLaurent Vivier 
346105683dSLaurent Vivier struct InputBarrier {
356105683dSLaurent Vivier     Object parent;
366105683dSLaurent Vivier 
376105683dSLaurent Vivier     QIOChannelSocket *sioc;
386105683dSLaurent Vivier     guint ioc_tag;
396105683dSLaurent Vivier 
406105683dSLaurent Vivier     /* display properties */
416105683dSLaurent Vivier     gchar *name;
426105683dSLaurent Vivier     int16_t x_origin, y_origin;
436105683dSLaurent Vivier     int16_t width, height;
446105683dSLaurent Vivier 
456105683dSLaurent Vivier     /* keyboard/mouse server */
466105683dSLaurent Vivier 
476105683dSLaurent Vivier     SocketAddress saddr;
486105683dSLaurent Vivier 
496105683dSLaurent Vivier     char buffer[MAX_HELLO_LENGTH];
506105683dSLaurent Vivier };
516105683dSLaurent Vivier 
526105683dSLaurent Vivier 
536105683dSLaurent Vivier static const char *cmd_names[] = {
546105683dSLaurent Vivier     [barrierCmdCNoop]          = "CNOP",
556105683dSLaurent Vivier     [barrierCmdCClose]         = "CBYE",
566105683dSLaurent Vivier     [barrierCmdCEnter]         = "CINN",
576105683dSLaurent Vivier     [barrierCmdCLeave]         = "COUT",
586105683dSLaurent Vivier     [barrierCmdCClipboard]     = "CCLP",
596105683dSLaurent Vivier     [barrierCmdCScreenSaver]   = "CSEC",
606105683dSLaurent Vivier     [barrierCmdCResetOptions]  = "CROP",
616105683dSLaurent Vivier     [barrierCmdCInfoAck]       = "CIAK",
626105683dSLaurent Vivier     [barrierCmdCKeepAlive]     = "CALV",
636105683dSLaurent Vivier     [barrierCmdDKeyDown]       = "DKDN",
646105683dSLaurent Vivier     [barrierCmdDKeyRepeat]     = "DKRP",
656105683dSLaurent Vivier     [barrierCmdDKeyUp]         = "DKUP",
666105683dSLaurent Vivier     [barrierCmdDMouseDown]     = "DMDN",
676105683dSLaurent Vivier     [barrierCmdDMouseUp]       = "DMUP",
686105683dSLaurent Vivier     [barrierCmdDMouseMove]     = "DMMV",
696105683dSLaurent Vivier     [barrierCmdDMouseRelMove]  = "DMRM",
706105683dSLaurent Vivier     [barrierCmdDMouseWheel]    = "DMWM",
716105683dSLaurent Vivier     [barrierCmdDClipboard]     = "DCLP",
726105683dSLaurent Vivier     [barrierCmdDInfo]          = "DINF",
736105683dSLaurent Vivier     [barrierCmdDSetOptions]    = "DSOP",
746105683dSLaurent Vivier     [barrierCmdDFileTransfer]  = "DFTR",
756105683dSLaurent Vivier     [barrierCmdDDragInfo]      = "DDRG",
766105683dSLaurent Vivier     [barrierCmdQInfo]          = "QINF",
776105683dSLaurent Vivier     [barrierCmdEIncompatible]  = "EICV",
786105683dSLaurent Vivier     [barrierCmdEBusy]          = "EBSY",
796105683dSLaurent Vivier     [barrierCmdEUnknown]       = "EUNK",
806105683dSLaurent Vivier     [barrierCmdEBad]           = "EBAD",
816105683dSLaurent Vivier     [barrierCmdHello]          = "Barrier",
826105683dSLaurent Vivier     [barrierCmdHelloBack]      = "Barrier",
836105683dSLaurent Vivier };
846105683dSLaurent Vivier 
856105683dSLaurent Vivier static kbd_layout_t *kbd_layout;
866105683dSLaurent Vivier 
input_barrier_to_qcode(uint16_t keyid,uint16_t keycode)876105683dSLaurent Vivier static int input_barrier_to_qcode(uint16_t keyid, uint16_t keycode)
886105683dSLaurent Vivier {
896105683dSLaurent Vivier     /* keycode is optional, if it is not provided use keyid */
906105683dSLaurent Vivier     if (keycode && keycode <= qemu_input_map_xorgkbd_to_qcode_len) {
916105683dSLaurent Vivier         return qemu_input_map_xorgkbd_to_qcode[keycode];
926105683dSLaurent Vivier     }
936105683dSLaurent Vivier 
946105683dSLaurent Vivier     if (keyid >= 0xE000 && keyid <= 0xEFFF) {
956105683dSLaurent Vivier         keyid += 0x1000;
966105683dSLaurent Vivier     }
976105683dSLaurent Vivier 
986105683dSLaurent Vivier     /* keyid is the X11 key id */
996105683dSLaurent Vivier     if (kbd_layout) {
1006105683dSLaurent Vivier         keycode = keysym2scancode(kbd_layout, keyid, NULL, false);
1016105683dSLaurent Vivier 
1026105683dSLaurent Vivier         return qemu_input_key_number_to_qcode(keycode);
1036105683dSLaurent Vivier     }
1046105683dSLaurent Vivier 
1056105683dSLaurent Vivier     return qemu_input_map_x11_to_qcode[keyid];
1066105683dSLaurent Vivier }
1076105683dSLaurent Vivier 
input_barrier_to_mouse(uint8_t buttonid)1086105683dSLaurent Vivier static int input_barrier_to_mouse(uint8_t buttonid)
1096105683dSLaurent Vivier {
1106105683dSLaurent Vivier     switch (buttonid) {
1116105683dSLaurent Vivier     case barrierButtonLeft:
1126105683dSLaurent Vivier         return INPUT_BUTTON_LEFT;
1136105683dSLaurent Vivier     case barrierButtonMiddle:
1146105683dSLaurent Vivier         return INPUT_BUTTON_MIDDLE;
1156105683dSLaurent Vivier     case barrierButtonRight:
1166105683dSLaurent Vivier         return INPUT_BUTTON_RIGHT;
1176105683dSLaurent Vivier     case barrierButtonExtra0:
1186105683dSLaurent Vivier         return INPUT_BUTTON_SIDE;
1196105683dSLaurent Vivier     }
1206105683dSLaurent Vivier     return buttonid;
1216105683dSLaurent Vivier }
1226105683dSLaurent Vivier 
1236105683dSLaurent Vivier #define read_char(x, p, l)           \
1246105683dSLaurent Vivier do {                                 \
1256105683dSLaurent Vivier     int size = sizeof(char);         \
1266105683dSLaurent Vivier     if (l < size) {                  \
1276105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1286105683dSLaurent Vivier     }                                \
1296105683dSLaurent Vivier     x = *(char *)p;                  \
1306105683dSLaurent Vivier     p += size;                       \
1316105683dSLaurent Vivier     l -= size;                       \
1326105683dSLaurent Vivier } while (0)
1336105683dSLaurent Vivier 
1346105683dSLaurent Vivier #define read_short(x, p, l)          \
1356105683dSLaurent Vivier do {                                 \
1366105683dSLaurent Vivier     int size = sizeof(short);        \
1376105683dSLaurent Vivier     if (l < size) {                  \
1386105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1396105683dSLaurent Vivier     }                                \
1406105683dSLaurent Vivier     x = ntohs(*(short *)p);          \
1416105683dSLaurent Vivier     p += size;                       \
1426105683dSLaurent Vivier     l -= size;                       \
1436105683dSLaurent Vivier } while (0)
1446105683dSLaurent Vivier 
1456105683dSLaurent Vivier #define write_short(p, x, l)         \
1466105683dSLaurent Vivier do {                                 \
1476105683dSLaurent Vivier     int size = sizeof(short);        \
1486105683dSLaurent Vivier     if (l < size) {                  \
1496105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1506105683dSLaurent Vivier     }                                \
1516105683dSLaurent Vivier     *(short *)p = htons(x);          \
1526105683dSLaurent Vivier     p += size;                       \
1536105683dSLaurent Vivier     l -= size;                       \
1546105683dSLaurent Vivier } while (0)
1556105683dSLaurent Vivier 
1566105683dSLaurent Vivier #define read_int(x, p, l)            \
1576105683dSLaurent Vivier do {                                 \
1586105683dSLaurent Vivier     int size = sizeof(int);          \
1596105683dSLaurent Vivier     if (l < size) {                  \
1606105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1616105683dSLaurent Vivier     }                                \
1626105683dSLaurent Vivier     x = ntohl(*(int *)p);            \
1636105683dSLaurent Vivier     p += size;                       \
1646105683dSLaurent Vivier     l -= size;                       \
1656105683dSLaurent Vivier } while (0)
1666105683dSLaurent Vivier 
1676105683dSLaurent Vivier #define write_int(p, x, l)           \
1686105683dSLaurent Vivier do {                                 \
1696105683dSLaurent Vivier     int size = sizeof(int);          \
1706105683dSLaurent Vivier     if (l < size) {                  \
1716105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1726105683dSLaurent Vivier     }                                \
1736105683dSLaurent Vivier     *(int *)p = htonl(x);            \
1746105683dSLaurent Vivier     p += size;                       \
1756105683dSLaurent Vivier     l -= size;                       \
1766105683dSLaurent Vivier } while (0)
1776105683dSLaurent Vivier 
1786105683dSLaurent Vivier #define write_cmd(p, c, l)           \
1796105683dSLaurent Vivier do {                                 \
1806105683dSLaurent Vivier     int size = strlen(cmd_names[c]); \
1816105683dSLaurent Vivier     if (l < size) {                  \
1826105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1836105683dSLaurent Vivier     }                                \
1846105683dSLaurent Vivier     memcpy(p, cmd_names[c], size);   \
1856105683dSLaurent Vivier     p += size;                       \
1866105683dSLaurent Vivier     l -= size;                       \
1876105683dSLaurent Vivier } while (0)
1886105683dSLaurent Vivier 
1896105683dSLaurent Vivier #define write_string(p, s, l)        \
1906105683dSLaurent Vivier do {                                 \
1916105683dSLaurent Vivier     int size = strlen(s);            \
1926105683dSLaurent Vivier     if (l < size + sizeof(int)) {    \
1936105683dSLaurent Vivier         return G_SOURCE_REMOVE;      \
1946105683dSLaurent Vivier     }                                \
1956105683dSLaurent Vivier     *(int *)p = htonl(size);         \
1966105683dSLaurent Vivier     p += sizeof(size);               \
1976105683dSLaurent Vivier     l -= sizeof(size);               \
1986105683dSLaurent Vivier     memcpy(p, s, size);              \
1996105683dSLaurent Vivier     p += size;                       \
2006105683dSLaurent Vivier     l -= size;                       \
2016105683dSLaurent Vivier } while (0)
2026105683dSLaurent Vivier 
readcmd(InputBarrier * ib,struct barrierMsg * msg)2036105683dSLaurent Vivier static gboolean readcmd(InputBarrier *ib, struct barrierMsg *msg)
2046105683dSLaurent Vivier {
2056105683dSLaurent Vivier     int ret, len, i;
2066105683dSLaurent Vivier     enum barrierCmd cmd;
2076105683dSLaurent Vivier     char *p;
2086105683dSLaurent Vivier 
2096105683dSLaurent Vivier     ret = qio_channel_read(QIO_CHANNEL(ib->sioc), (char *)&len, sizeof(len),
2106105683dSLaurent Vivier                            NULL);
2116105683dSLaurent Vivier     if (ret < 0) {
2126105683dSLaurent Vivier         return G_SOURCE_REMOVE;
2136105683dSLaurent Vivier     }
2146105683dSLaurent Vivier 
2156105683dSLaurent Vivier     len = ntohl(len);
2166105683dSLaurent Vivier     if (len > MAX_HELLO_LENGTH) {
2176105683dSLaurent Vivier         return G_SOURCE_REMOVE;
2186105683dSLaurent Vivier     }
2196105683dSLaurent Vivier 
2206105683dSLaurent Vivier     ret = qio_channel_read(QIO_CHANNEL(ib->sioc), ib->buffer, len, NULL);
2216105683dSLaurent Vivier     if (ret < 0) {
2226105683dSLaurent Vivier         return G_SOURCE_REMOVE;
2236105683dSLaurent Vivier     }
2246105683dSLaurent Vivier 
2256105683dSLaurent Vivier     p = ib->buffer;
2266105683dSLaurent Vivier     if (len >= strlen(cmd_names[barrierCmdHello]) &&
2276105683dSLaurent Vivier         memcmp(p, cmd_names[barrierCmdHello],
2286105683dSLaurent Vivier                strlen(cmd_names[barrierCmdHello])) == 0) {
2296105683dSLaurent Vivier         cmd = barrierCmdHello;
2306105683dSLaurent Vivier         p += strlen(cmd_names[barrierCmdHello]);
2316105683dSLaurent Vivier         len -= strlen(cmd_names[barrierCmdHello]);
2326105683dSLaurent Vivier     } else {
2336105683dSLaurent Vivier         for (cmd = 0; cmd < barrierCmdHello; cmd++) {
2346105683dSLaurent Vivier             if (memcmp(ib->buffer, cmd_names[cmd], 4) == 0) {
2356105683dSLaurent Vivier                 break;
2366105683dSLaurent Vivier             }
2376105683dSLaurent Vivier         }
2386105683dSLaurent Vivier 
2396105683dSLaurent Vivier         if (cmd == barrierCmdHello) {
2406105683dSLaurent Vivier             return G_SOURCE_REMOVE;
2416105683dSLaurent Vivier         }
2426105683dSLaurent Vivier         p += 4;
2436105683dSLaurent Vivier         len -= 4;
2446105683dSLaurent Vivier     }
2456105683dSLaurent Vivier 
2466105683dSLaurent Vivier     msg->cmd = cmd;
2476105683dSLaurent Vivier     switch (cmd) {
2486105683dSLaurent Vivier     /* connection */
2496105683dSLaurent Vivier     case barrierCmdHello:
2506105683dSLaurent Vivier         read_short(msg->version.major, p, len);
2516105683dSLaurent Vivier         read_short(msg->version.minor, p, len);
2526105683dSLaurent Vivier         break;
2536105683dSLaurent Vivier     case barrierCmdDSetOptions:
2546105683dSLaurent Vivier         read_int(msg->set.nb, p, len);
2556105683dSLaurent Vivier         msg->set.nb /= 2;
2566105683dSLaurent Vivier         if (msg->set.nb > BARRIER_MAX_OPTIONS) {
2576105683dSLaurent Vivier             msg->set.nb = BARRIER_MAX_OPTIONS;
2586105683dSLaurent Vivier         }
2596105683dSLaurent Vivier         i = 0;
2606105683dSLaurent Vivier         while (len && i < msg->set.nb) {
2616105683dSLaurent Vivier             read_int(msg->set.option[i].id, p, len);
2626105683dSLaurent Vivier             /* it's a string, restore endianness */
2636105683dSLaurent Vivier             msg->set.option[i].id = htonl(msg->set.option[i].id);
2646105683dSLaurent Vivier             msg->set.option[i].nul = 0;
2656105683dSLaurent Vivier             read_int(msg->set.option[i].value, p, len);
2666105683dSLaurent Vivier             i++;
2676105683dSLaurent Vivier         }
2686105683dSLaurent Vivier         break;
2696105683dSLaurent Vivier     case barrierCmdQInfo:
2706105683dSLaurent Vivier         break;
2716105683dSLaurent Vivier 
2726105683dSLaurent Vivier     /* mouse */
2736105683dSLaurent Vivier     case barrierCmdDMouseMove:
2746105683dSLaurent Vivier     case barrierCmdDMouseRelMove:
2756105683dSLaurent Vivier         read_short(msg->mousepos.x, p, len);
2766105683dSLaurent Vivier         read_short(msg->mousepos.y, p, len);
2776105683dSLaurent Vivier         break;
2786105683dSLaurent Vivier     case barrierCmdDMouseDown:
2796105683dSLaurent Vivier     case barrierCmdDMouseUp:
2806105683dSLaurent Vivier         read_char(msg->mousebutton.buttonid, p, len);
2816105683dSLaurent Vivier         break;
2826105683dSLaurent Vivier     case barrierCmdDMouseWheel:
2836105683dSLaurent Vivier         read_short(msg->mousepos.y, p, len);
2846105683dSLaurent Vivier         msg->mousepos.x = 0;
2856105683dSLaurent Vivier         if (len) {
2866105683dSLaurent Vivier             msg->mousepos.x = msg->mousepos.y;
2876105683dSLaurent Vivier             read_short(msg->mousepos.y, p, len);
2886105683dSLaurent Vivier         }
2896105683dSLaurent Vivier         break;
2906105683dSLaurent Vivier 
2916105683dSLaurent Vivier     /* keyboard */
2926105683dSLaurent Vivier     case barrierCmdDKeyDown:
2936105683dSLaurent Vivier     case barrierCmdDKeyUp:
2946105683dSLaurent Vivier         read_short(msg->key.keyid, p, len);
2956105683dSLaurent Vivier         read_short(msg->key.modifier, p, len);
2966105683dSLaurent Vivier         msg->key.button = 0;
2976105683dSLaurent Vivier         if (len) {
2986105683dSLaurent Vivier             read_short(msg->key.button, p, len);
2996105683dSLaurent Vivier         }
3006105683dSLaurent Vivier         break;
3016105683dSLaurent Vivier     case barrierCmdDKeyRepeat:
3026105683dSLaurent Vivier         read_short(msg->repeat.keyid, p, len);
3036105683dSLaurent Vivier         read_short(msg->repeat.modifier, p, len);
3046105683dSLaurent Vivier         read_short(msg->repeat.repeat, p, len);
3056105683dSLaurent Vivier         msg->repeat.button = 0;
3066105683dSLaurent Vivier         if (len) {
3076105683dSLaurent Vivier             read_short(msg->repeat.button, p, len);
3086105683dSLaurent Vivier         }
3096105683dSLaurent Vivier         break;
3106105683dSLaurent Vivier     case barrierCmdCInfoAck:
3116105683dSLaurent Vivier     case barrierCmdCResetOptions:
3126105683dSLaurent Vivier     case barrierCmdCEnter:
3136105683dSLaurent Vivier     case barrierCmdDClipboard:
3146105683dSLaurent Vivier     case barrierCmdCKeepAlive:
3156105683dSLaurent Vivier     case barrierCmdCLeave:
3166105683dSLaurent Vivier     case barrierCmdCClose:
3176105683dSLaurent Vivier         break;
3186105683dSLaurent Vivier 
3196105683dSLaurent Vivier     /* Invalid from the server */
3206105683dSLaurent Vivier     case barrierCmdHelloBack:
3216105683dSLaurent Vivier     case barrierCmdCNoop:
3226105683dSLaurent Vivier     case barrierCmdDInfo:
3236105683dSLaurent Vivier         break;
3246105683dSLaurent Vivier 
3256105683dSLaurent Vivier     /* Error codes */
3266105683dSLaurent Vivier     case barrierCmdEIncompatible:
3276105683dSLaurent Vivier         read_short(msg->version.major, p, len);
3286105683dSLaurent Vivier         read_short(msg->version.minor, p, len);
3296105683dSLaurent Vivier         break;
3306105683dSLaurent Vivier     case barrierCmdEBusy:
3316105683dSLaurent Vivier     case barrierCmdEUnknown:
3326105683dSLaurent Vivier     case barrierCmdEBad:
3336105683dSLaurent Vivier         break;
3346105683dSLaurent Vivier     default:
3356105683dSLaurent Vivier         return G_SOURCE_REMOVE;
3366105683dSLaurent Vivier     }
3376105683dSLaurent Vivier 
3386105683dSLaurent Vivier     return G_SOURCE_CONTINUE;
3396105683dSLaurent Vivier }
3406105683dSLaurent Vivier 
writecmd(InputBarrier * ib,struct barrierMsg * msg)3416105683dSLaurent Vivier static gboolean writecmd(InputBarrier *ib, struct barrierMsg *msg)
3426105683dSLaurent Vivier {
3436105683dSLaurent Vivier     char *p;
3446105683dSLaurent Vivier     int ret, i;
3456105683dSLaurent Vivier     int avail, len;
3466105683dSLaurent Vivier 
3476105683dSLaurent Vivier     p = ib->buffer;
3486105683dSLaurent Vivier     avail = MAX_HELLO_LENGTH;
3496105683dSLaurent Vivier 
3506105683dSLaurent Vivier     /* reserve space to store the length */
3516105683dSLaurent Vivier     p += sizeof(int);
3526105683dSLaurent Vivier     avail -= sizeof(int);
3536105683dSLaurent Vivier 
3546105683dSLaurent Vivier     switch (msg->cmd) {
3556105683dSLaurent Vivier     case barrierCmdHello:
3566105683dSLaurent Vivier         if (msg->version.major < BARRIER_VERSION_MAJOR ||
3576105683dSLaurent Vivier             (msg->version.major == BARRIER_VERSION_MAJOR &&
3586105683dSLaurent Vivier              msg->version.minor < BARRIER_VERSION_MINOR)) {
3596105683dSLaurent Vivier             ib->ioc_tag = 0;
3606105683dSLaurent Vivier             return G_SOURCE_REMOVE;
3616105683dSLaurent Vivier         }
3626105683dSLaurent Vivier         write_cmd(p, barrierCmdHelloBack, avail);
3636105683dSLaurent Vivier         write_short(p, BARRIER_VERSION_MAJOR, avail);
3646105683dSLaurent Vivier         write_short(p, BARRIER_VERSION_MINOR, avail);
3656105683dSLaurent Vivier         write_string(p, ib->name, avail);
3666105683dSLaurent Vivier         break;
3676105683dSLaurent Vivier     case barrierCmdCClose:
3686105683dSLaurent Vivier         ib->ioc_tag = 0;
3696105683dSLaurent Vivier         return G_SOURCE_REMOVE;
3706105683dSLaurent Vivier     case barrierCmdQInfo:
3716105683dSLaurent Vivier         write_cmd(p, barrierCmdDInfo, avail);
3726105683dSLaurent Vivier         write_short(p, ib->x_origin, avail);
3736105683dSLaurent Vivier         write_short(p, ib->y_origin, avail);
3746105683dSLaurent Vivier         write_short(p, ib->width, avail);
3756105683dSLaurent Vivier         write_short(p, ib->height, avail);
3766105683dSLaurent Vivier         write_short(p, 0, avail);    /* warpsize (obsolete) */
3776105683dSLaurent Vivier         write_short(p, 0, avail);    /* mouse x */
3786105683dSLaurent Vivier         write_short(p, 0, avail);    /* mouse y */
3796105683dSLaurent Vivier         break;
3806105683dSLaurent Vivier     case barrierCmdCInfoAck:
3816105683dSLaurent Vivier         break;
3826105683dSLaurent Vivier     case barrierCmdCResetOptions:
3836105683dSLaurent Vivier         /* TODO: reset options */
3846105683dSLaurent Vivier         break;
3856105683dSLaurent Vivier     case barrierCmdDSetOptions:
3866105683dSLaurent Vivier         /* TODO: set options */
3876105683dSLaurent Vivier         break;
3886105683dSLaurent Vivier     case barrierCmdCEnter:
3896105683dSLaurent Vivier         break;
3906105683dSLaurent Vivier     case barrierCmdDClipboard:
3916105683dSLaurent Vivier         break;
3926105683dSLaurent Vivier     case barrierCmdCKeepAlive:
3936105683dSLaurent Vivier         write_cmd(p, barrierCmdCKeepAlive, avail);
3946105683dSLaurent Vivier         break;
3956105683dSLaurent Vivier     case barrierCmdCLeave:
3966105683dSLaurent Vivier         break;
3976105683dSLaurent Vivier 
3986105683dSLaurent Vivier     /* mouse */
3996105683dSLaurent Vivier     case barrierCmdDMouseMove:
4006105683dSLaurent Vivier         qemu_input_queue_abs(NULL, INPUT_AXIS_X, msg->mousepos.x,
4016105683dSLaurent Vivier                              ib->x_origin, ib->width);
4026105683dSLaurent Vivier         qemu_input_queue_abs(NULL, INPUT_AXIS_Y, msg->mousepos.y,
4036105683dSLaurent Vivier                              ib->y_origin, ib->height);
4046105683dSLaurent Vivier         qemu_input_event_sync();
4056105683dSLaurent Vivier         break;
4066105683dSLaurent Vivier     case barrierCmdDMouseRelMove:
4076105683dSLaurent Vivier         qemu_input_queue_rel(NULL, INPUT_AXIS_X, msg->mousepos.x);
4086105683dSLaurent Vivier         qemu_input_queue_rel(NULL, INPUT_AXIS_Y, msg->mousepos.y);
4096105683dSLaurent Vivier         qemu_input_event_sync();
4106105683dSLaurent Vivier         break;
4116105683dSLaurent Vivier     case barrierCmdDMouseDown:
4126105683dSLaurent Vivier         qemu_input_queue_btn(NULL,
4136105683dSLaurent Vivier                              input_barrier_to_mouse(msg->mousebutton.buttonid),
4146105683dSLaurent Vivier                              true);
4156105683dSLaurent Vivier         qemu_input_event_sync();
4166105683dSLaurent Vivier         break;
4176105683dSLaurent Vivier     case barrierCmdDMouseUp:
4186105683dSLaurent Vivier         qemu_input_queue_btn(NULL,
4196105683dSLaurent Vivier                              input_barrier_to_mouse(msg->mousebutton.buttonid),
4206105683dSLaurent Vivier                              false);
4216105683dSLaurent Vivier         qemu_input_event_sync();
4226105683dSLaurent Vivier         break;
4236105683dSLaurent Vivier     case barrierCmdDMouseWheel:
4246105683dSLaurent Vivier         qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
4256105683dSLaurent Vivier                              : INPUT_BUTTON_WHEEL_DOWN, true);
4266105683dSLaurent Vivier         qemu_input_event_sync();
4276105683dSLaurent Vivier         qemu_input_queue_btn(NULL, (msg->mousepos.y > 0) ? INPUT_BUTTON_WHEEL_UP
4286105683dSLaurent Vivier                              : INPUT_BUTTON_WHEEL_DOWN, false);
4296105683dSLaurent Vivier         qemu_input_event_sync();
4306105683dSLaurent Vivier         break;
4316105683dSLaurent Vivier 
4326105683dSLaurent Vivier     /* keyboard */
4336105683dSLaurent Vivier     case barrierCmdDKeyDown:
4346105683dSLaurent Vivier         qemu_input_event_send_key_qcode(NULL,
4356105683dSLaurent Vivier                         input_barrier_to_qcode(msg->key.keyid, msg->key.button),
4366105683dSLaurent Vivier                                         true);
4376105683dSLaurent Vivier         break;
4386105683dSLaurent Vivier     case barrierCmdDKeyRepeat:
4396105683dSLaurent Vivier         for (i = 0; i < msg->repeat.repeat; i++) {
4406105683dSLaurent Vivier             qemu_input_event_send_key_qcode(NULL,
4416105683dSLaurent Vivier                   input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
4426105683dSLaurent Vivier                                             false);
4436105683dSLaurent Vivier             qemu_input_event_send_key_qcode(NULL,
4446105683dSLaurent Vivier                   input_barrier_to_qcode(msg->repeat.keyid, msg->repeat.button),
4456105683dSLaurent Vivier                                             true);
4466105683dSLaurent Vivier         }
4476105683dSLaurent Vivier         break;
4486105683dSLaurent Vivier     case barrierCmdDKeyUp:
4496105683dSLaurent Vivier         qemu_input_event_send_key_qcode(NULL,
4506105683dSLaurent Vivier                         input_barrier_to_qcode(msg->key.keyid, msg->key.button),
4516105683dSLaurent Vivier                                         false);
4526105683dSLaurent Vivier         break;
4536105683dSLaurent Vivier     default:
4546105683dSLaurent Vivier         write_cmd(p, barrierCmdEUnknown, avail);
45529453426SPhilippe Mathieu-Daudé         break;
4566105683dSLaurent Vivier     }
4576105683dSLaurent Vivier 
4586105683dSLaurent Vivier     len = MAX_HELLO_LENGTH - avail - sizeof(int);
4596105683dSLaurent Vivier     if (len) {
4606105683dSLaurent Vivier         p = ib->buffer;
4616105683dSLaurent Vivier         avail = sizeof(len);
4626105683dSLaurent Vivier         write_int(p, len, avail);
4636105683dSLaurent Vivier         ret = qio_channel_write(QIO_CHANNEL(ib->sioc), ib->buffer,
4646105683dSLaurent Vivier                                 len + sizeof(len), NULL);
4656105683dSLaurent Vivier         if (ret < 0) {
4666105683dSLaurent Vivier             ib->ioc_tag = 0;
4676105683dSLaurent Vivier             return G_SOURCE_REMOVE;
4686105683dSLaurent Vivier         }
4696105683dSLaurent Vivier     }
4706105683dSLaurent Vivier 
4716105683dSLaurent Vivier     return G_SOURCE_CONTINUE;
4726105683dSLaurent Vivier }
4736105683dSLaurent Vivier 
input_barrier_event(QIOChannel * ioc G_GNUC_UNUSED,GIOCondition condition,void * opaque)4746105683dSLaurent Vivier static gboolean input_barrier_event(QIOChannel *ioc G_GNUC_UNUSED,
4756105683dSLaurent Vivier                                     GIOCondition condition, void *opaque)
4766105683dSLaurent Vivier {
4776105683dSLaurent Vivier     InputBarrier *ib = opaque;
4786105683dSLaurent Vivier     int ret;
4796105683dSLaurent Vivier     struct barrierMsg msg;
4806105683dSLaurent Vivier 
4816105683dSLaurent Vivier     ret = readcmd(ib, &msg);
4826105683dSLaurent Vivier     if (ret == G_SOURCE_REMOVE) {
4836105683dSLaurent Vivier         ib->ioc_tag = 0;
4846105683dSLaurent Vivier         return G_SOURCE_REMOVE;
4856105683dSLaurent Vivier     }
4866105683dSLaurent Vivier 
4876105683dSLaurent Vivier     return writecmd(ib, &msg);
4886105683dSLaurent Vivier }
4896105683dSLaurent Vivier 
input_barrier_complete(UserCreatable * uc,Error ** errp)4906105683dSLaurent Vivier static void input_barrier_complete(UserCreatable *uc, Error **errp)
4916105683dSLaurent Vivier {
4926105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(uc);
4936105683dSLaurent Vivier     Error *local_err = NULL;
4946105683dSLaurent Vivier 
4956105683dSLaurent Vivier     if (!ib->name) {
4966105683dSLaurent Vivier         error_setg(errp, QERR_MISSING_PARAMETER, "name");
4976105683dSLaurent Vivier         return;
4986105683dSLaurent Vivier     }
4996105683dSLaurent Vivier 
5006105683dSLaurent Vivier     /*
5016105683dSLaurent Vivier      * Connect to the primary
5026105683dSLaurent Vivier      * Primary is the server where the keyboard and the mouse
5036105683dSLaurent Vivier      * are connected and forwarded to the secondary (the client)
5046105683dSLaurent Vivier      */
5056105683dSLaurent Vivier 
5066105683dSLaurent Vivier     ib->sioc = qio_channel_socket_new();
5076105683dSLaurent Vivier     qio_channel_set_name(QIO_CHANNEL(ib->sioc), "barrier-client");
5086105683dSLaurent Vivier 
5096105683dSLaurent Vivier     qio_channel_socket_connect_sync(ib->sioc, &ib->saddr, &local_err);
5106105683dSLaurent Vivier     if (local_err) {
5116105683dSLaurent Vivier         error_propagate(errp, local_err);
5126105683dSLaurent Vivier         return;
5136105683dSLaurent Vivier     }
5146105683dSLaurent Vivier 
5156105683dSLaurent Vivier     qio_channel_set_delay(QIO_CHANNEL(ib->sioc), false);
5166105683dSLaurent Vivier 
5176105683dSLaurent Vivier     ib->ioc_tag = qio_channel_add_watch(QIO_CHANNEL(ib->sioc), G_IO_IN,
5186105683dSLaurent Vivier                                         input_barrier_event, ib, NULL);
5196105683dSLaurent Vivier }
5206105683dSLaurent Vivier 
input_barrier_instance_finalize(Object * obj)5216105683dSLaurent Vivier static void input_barrier_instance_finalize(Object *obj)
5226105683dSLaurent Vivier {
5236105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5246105683dSLaurent Vivier 
5256105683dSLaurent Vivier     if (ib->ioc_tag) {
5266105683dSLaurent Vivier         g_source_remove(ib->ioc_tag);
5276105683dSLaurent Vivier         ib->ioc_tag = 0;
5286105683dSLaurent Vivier     }
5296105683dSLaurent Vivier 
5306105683dSLaurent Vivier     if (ib->sioc) {
5316105683dSLaurent Vivier         qio_channel_close(QIO_CHANNEL(ib->sioc), NULL);
5326105683dSLaurent Vivier         object_unref(OBJECT(ib->sioc));
5336105683dSLaurent Vivier     }
5346105683dSLaurent Vivier     g_free(ib->name);
5356105683dSLaurent Vivier     g_free(ib->saddr.u.inet.host);
5366105683dSLaurent Vivier     g_free(ib->saddr.u.inet.port);
5376105683dSLaurent Vivier }
5386105683dSLaurent Vivier 
input_barrier_get_name(Object * obj,Error ** errp)5396105683dSLaurent Vivier static char *input_barrier_get_name(Object *obj, Error **errp)
5406105683dSLaurent Vivier {
5416105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5426105683dSLaurent Vivier 
5436105683dSLaurent Vivier     return g_strdup(ib->name);
5446105683dSLaurent Vivier }
5456105683dSLaurent Vivier 
input_barrier_set_name(Object * obj,const char * value,Error ** errp)5466105683dSLaurent Vivier static void input_barrier_set_name(Object *obj, const char *value,
5476105683dSLaurent Vivier                                   Error **errp)
5486105683dSLaurent Vivier {
5496105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5506105683dSLaurent Vivier 
5516105683dSLaurent Vivier     if (ib->name) {
5526105683dSLaurent Vivier         error_setg(errp, "name property already set");
5536105683dSLaurent Vivier         return;
5546105683dSLaurent Vivier     }
5556105683dSLaurent Vivier     ib->name = g_strdup(value);
5566105683dSLaurent Vivier }
5576105683dSLaurent Vivier 
input_barrier_get_server(Object * obj,Error ** errp)5586105683dSLaurent Vivier static char *input_barrier_get_server(Object *obj, Error **errp)
5596105683dSLaurent Vivier {
5606105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5616105683dSLaurent Vivier 
5626105683dSLaurent Vivier     return g_strdup(ib->saddr.u.inet.host);
5636105683dSLaurent Vivier }
5646105683dSLaurent Vivier 
input_barrier_set_server(Object * obj,const char * value,Error ** errp)5656105683dSLaurent Vivier static void input_barrier_set_server(Object *obj, const char *value,
5666105683dSLaurent Vivier                                      Error **errp)
5676105683dSLaurent Vivier {
5686105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5696105683dSLaurent Vivier 
5706105683dSLaurent Vivier     g_free(ib->saddr.u.inet.host);
5716105683dSLaurent Vivier     ib->saddr.u.inet.host = g_strdup(value);
5726105683dSLaurent Vivier }
5736105683dSLaurent Vivier 
input_barrier_get_port(Object * obj,Error ** errp)5746105683dSLaurent Vivier static char *input_barrier_get_port(Object *obj, Error **errp)
5756105683dSLaurent Vivier {
5766105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5776105683dSLaurent Vivier 
5786105683dSLaurent Vivier     return g_strdup(ib->saddr.u.inet.port);
5796105683dSLaurent Vivier }
5806105683dSLaurent Vivier 
input_barrier_set_port(Object * obj,const char * value,Error ** errp)5816105683dSLaurent Vivier static void input_barrier_set_port(Object *obj, const char *value,
5826105683dSLaurent Vivier                                      Error **errp)
5836105683dSLaurent Vivier {
5846105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5856105683dSLaurent Vivier 
5866105683dSLaurent Vivier     g_free(ib->saddr.u.inet.port);
5876105683dSLaurent Vivier     ib->saddr.u.inet.port = g_strdup(value);
5886105683dSLaurent Vivier }
5896105683dSLaurent Vivier 
input_barrier_set_x_origin(Object * obj,const char * value,Error ** errp)5906105683dSLaurent Vivier static void input_barrier_set_x_origin(Object *obj, const char *value,
5916105683dSLaurent Vivier                                        Error **errp)
5926105683dSLaurent Vivier {
5936105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
5946105683dSLaurent Vivier     int result, err;
5956105683dSLaurent Vivier 
5966105683dSLaurent Vivier     err = qemu_strtoi(value, NULL, 0, &result);
5976105683dSLaurent Vivier     if (err < 0 || result < 0 || result > SHRT_MAX) {
5986105683dSLaurent Vivier         error_setg(errp,
5996105683dSLaurent Vivier                    "x-origin property must be in the range [0..%d]", SHRT_MAX);
6006105683dSLaurent Vivier         return;
6016105683dSLaurent Vivier     }
6026105683dSLaurent Vivier     ib->x_origin = result;
6036105683dSLaurent Vivier }
6046105683dSLaurent Vivier 
input_barrier_get_x_origin(Object * obj,Error ** errp)6056105683dSLaurent Vivier static char *input_barrier_get_x_origin(Object *obj, Error **errp)
6066105683dSLaurent Vivier {
6076105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6086105683dSLaurent Vivier 
6096105683dSLaurent Vivier     return g_strdup_printf("%d", ib->x_origin);
6106105683dSLaurent Vivier }
6116105683dSLaurent Vivier 
input_barrier_set_y_origin(Object * obj,const char * value,Error ** errp)6126105683dSLaurent Vivier static void input_barrier_set_y_origin(Object *obj, const char *value,
6136105683dSLaurent Vivier                                        Error **errp)
6146105683dSLaurent Vivier {
6156105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6166105683dSLaurent Vivier     int result, err;
6176105683dSLaurent Vivier 
6186105683dSLaurent Vivier     err = qemu_strtoi(value, NULL, 0, &result);
6196105683dSLaurent Vivier     if (err < 0 || result < 0 || result > SHRT_MAX) {
6206105683dSLaurent Vivier         error_setg(errp,
6216105683dSLaurent Vivier                    "y-origin property must be in the range [0..%d]", SHRT_MAX);
6226105683dSLaurent Vivier         return;
6236105683dSLaurent Vivier     }
6246105683dSLaurent Vivier     ib->y_origin = result;
6256105683dSLaurent Vivier }
6266105683dSLaurent Vivier 
input_barrier_get_y_origin(Object * obj,Error ** errp)6276105683dSLaurent Vivier static char *input_barrier_get_y_origin(Object *obj, Error **errp)
6286105683dSLaurent Vivier {
6296105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6306105683dSLaurent Vivier 
6316105683dSLaurent Vivier     return g_strdup_printf("%d", ib->y_origin);
6326105683dSLaurent Vivier }
6336105683dSLaurent Vivier 
input_barrier_set_width(Object * obj,const char * value,Error ** errp)6346105683dSLaurent Vivier static void input_barrier_set_width(Object *obj, const char *value,
6356105683dSLaurent Vivier                                        Error **errp)
6366105683dSLaurent Vivier {
6376105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6386105683dSLaurent Vivier     int result, err;
6396105683dSLaurent Vivier 
6406105683dSLaurent Vivier     err = qemu_strtoi(value, NULL, 0, &result);
6416105683dSLaurent Vivier     if (err < 0 || result < 0 || result > SHRT_MAX) {
6426105683dSLaurent Vivier         error_setg(errp,
6436105683dSLaurent Vivier                    "width property must be in the range [0..%d]", SHRT_MAX);
6446105683dSLaurent Vivier         return;
6456105683dSLaurent Vivier     }
6466105683dSLaurent Vivier     ib->width = result;
6476105683dSLaurent Vivier }
6486105683dSLaurent Vivier 
input_barrier_get_width(Object * obj,Error ** errp)6496105683dSLaurent Vivier static char *input_barrier_get_width(Object *obj, Error **errp)
6506105683dSLaurent Vivier {
6516105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6526105683dSLaurent Vivier 
6536105683dSLaurent Vivier     return g_strdup_printf("%d", ib->width);
6546105683dSLaurent Vivier }
6556105683dSLaurent Vivier 
input_barrier_set_height(Object * obj,const char * value,Error ** errp)6566105683dSLaurent Vivier static void input_barrier_set_height(Object *obj, const char *value,
6576105683dSLaurent Vivier                                        Error **errp)
6586105683dSLaurent Vivier {
6596105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6606105683dSLaurent Vivier     int result, err;
6616105683dSLaurent Vivier 
6626105683dSLaurent Vivier     err = qemu_strtoi(value, NULL, 0, &result);
6636105683dSLaurent Vivier     if (err < 0 || result < 0 || result > SHRT_MAX) {
6646105683dSLaurent Vivier         error_setg(errp,
6656105683dSLaurent Vivier                    "height property must be in the range [0..%d]", SHRT_MAX);
6666105683dSLaurent Vivier         return;
6676105683dSLaurent Vivier     }
6686105683dSLaurent Vivier     ib->height = result;
6696105683dSLaurent Vivier }
6706105683dSLaurent Vivier 
input_barrier_get_height(Object * obj,Error ** errp)6716105683dSLaurent Vivier static char *input_barrier_get_height(Object *obj, Error **errp)
6726105683dSLaurent Vivier {
6736105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6746105683dSLaurent Vivier 
6756105683dSLaurent Vivier     return g_strdup_printf("%d", ib->height);
6766105683dSLaurent Vivier }
6776105683dSLaurent Vivier 
input_barrier_instance_init(Object * obj)6786105683dSLaurent Vivier static void input_barrier_instance_init(Object *obj)
6796105683dSLaurent Vivier {
6806105683dSLaurent Vivier     InputBarrier *ib = INPUT_BARRIER(obj);
6816105683dSLaurent Vivier 
682707f7507SLaurent Vivier     /* always use generic keymaps */
683707f7507SLaurent Vivier     if (keyboard_layout && !kbd_layout) {
684707f7507SLaurent Vivier         /* We use X11 key id, so use VNC name2keysym */
685707f7507SLaurent Vivier         kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
686707f7507SLaurent Vivier                                           &error_fatal);
687707f7507SLaurent Vivier     }
688707f7507SLaurent Vivier 
6896105683dSLaurent Vivier     ib->saddr.type = SOCKET_ADDRESS_TYPE_INET;
6906105683dSLaurent Vivier     ib->saddr.u.inet.host = g_strdup("localhost");
6916105683dSLaurent Vivier     ib->saddr.u.inet.port = g_strdup("24800");
6926105683dSLaurent Vivier 
6936105683dSLaurent Vivier     ib->x_origin = 0;
6946105683dSLaurent Vivier     ib->y_origin = 0;
6956105683dSLaurent Vivier     ib->width = 1920;
6966105683dSLaurent Vivier     ib->height = 1080;
6976105683dSLaurent Vivier }
6986105683dSLaurent Vivier 
input_barrier_class_init(ObjectClass * oc,void * data)6996105683dSLaurent Vivier static void input_barrier_class_init(ObjectClass *oc, void *data)
7006105683dSLaurent Vivier {
7016105683dSLaurent Vivier     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
7026105683dSLaurent Vivier 
7036105683dSLaurent Vivier     ucc->complete = input_barrier_complete;
704d85855b8SEduardo Habkost 
705d85855b8SEduardo Habkost     object_class_property_add_str(oc, "name",
706d85855b8SEduardo Habkost                                   input_barrier_get_name,
707d85855b8SEduardo Habkost                                   input_barrier_set_name);
708d85855b8SEduardo Habkost     object_class_property_add_str(oc, "server",
709d85855b8SEduardo Habkost                                   input_barrier_get_server,
710d85855b8SEduardo Habkost                                   input_barrier_set_server);
711d85855b8SEduardo Habkost     object_class_property_add_str(oc, "port",
712d85855b8SEduardo Habkost                                   input_barrier_get_port,
713d85855b8SEduardo Habkost                                   input_barrier_set_port);
714d85855b8SEduardo Habkost     object_class_property_add_str(oc, "x-origin",
715d85855b8SEduardo Habkost                                   input_barrier_get_x_origin,
716d85855b8SEduardo Habkost                                   input_barrier_set_x_origin);
717d85855b8SEduardo Habkost     object_class_property_add_str(oc, "y-origin",
718d85855b8SEduardo Habkost                                   input_barrier_get_y_origin,
719d85855b8SEduardo Habkost                                   input_barrier_set_y_origin);
720d85855b8SEduardo Habkost     object_class_property_add_str(oc, "width",
721d85855b8SEduardo Habkost                                   input_barrier_get_width,
722d85855b8SEduardo Habkost                                   input_barrier_set_width);
723d85855b8SEduardo Habkost     object_class_property_add_str(oc, "height",
724d85855b8SEduardo Habkost                                   input_barrier_get_height,
725d85855b8SEduardo Habkost                                   input_barrier_set_height);
7266105683dSLaurent Vivier }
7276105683dSLaurent Vivier 
7286105683dSLaurent Vivier static const TypeInfo input_barrier_info = {
7296105683dSLaurent Vivier     .name = TYPE_INPUT_BARRIER,
7306105683dSLaurent Vivier     .parent = TYPE_OBJECT,
7316105683dSLaurent Vivier     .class_init = input_barrier_class_init,
7326105683dSLaurent Vivier     .instance_size = sizeof(InputBarrier),
7336105683dSLaurent Vivier     .instance_init = input_barrier_instance_init,
7346105683dSLaurent Vivier     .instance_finalize = input_barrier_instance_finalize,
7356105683dSLaurent Vivier     .interfaces = (InterfaceInfo[]) {
7366105683dSLaurent Vivier         { TYPE_USER_CREATABLE },
7376105683dSLaurent Vivier         { }
7386105683dSLaurent Vivier     }
7396105683dSLaurent Vivier };
7406105683dSLaurent Vivier 
register_types(void)7416105683dSLaurent Vivier static void register_types(void)
7426105683dSLaurent Vivier {
7436105683dSLaurent Vivier     type_register_static(&input_barrier_info);
7446105683dSLaurent Vivier }
7456105683dSLaurent Vivier 
7466105683dSLaurent Vivier type_init(register_types);
747