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