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 * TODO:
   8 *
   9 *  - Enable SSL
  10 *  - Manage SetOptions/ResetOptions commands
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "sysemu/sysemu.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"
  28OBJECT_DECLARE_SIMPLE_TYPE(InputBarrier,
  29                           INPUT_BARRIER)
  30
  31
  32#define MAX_HELLO_LENGTH 1024
  33
  34struct 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
  53static 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
  85static kbd_layout_t *kbd_layout;
  86
  87static 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
 108static 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)           \
 124do {                                 \
 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)          \
 135do {                                 \
 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)         \
 146do {                                 \
 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)            \
 157do {                                 \
 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)           \
 168do {                                 \
 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)           \
 179do {                                 \
 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)        \
 190do {                                 \
 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
 203static 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
 341static 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
 474static 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
 490static void input_barrier_complete(UserCreatable *uc, Error **errp)
 491{
 492    InputBarrier *ib = INPUT_BARRIER(uc);
 493    Error *local_err = NULL;
 494
 495    if (!ib->name) {
 496        error_setg(errp, QERR_MISSING_PARAMETER, "name");
 497        return;
 498    }
 499
 500    /*
 501     * Connect to the primary
 502     * Primary is the server where the keyboard and the mouse
 503     * are connected and forwarded to the secondary (the client)
 504     */
 505
 506    ib->sioc = qio_channel_socket_new();
 507    qio_channel_set_name(QIO_CHANNEL(ib->sioc), "barrier-client");
 508
 509    qio_channel_socket_connect_sync(ib->sioc, &ib->saddr, &local_err);
 510    if (local_err) {
 511        error_propagate(errp, local_err);
 512        return;
 513    }
 514
 515    qio_channel_set_delay(QIO_CHANNEL(ib->sioc), false);
 516
 517    ib->ioc_tag = qio_channel_add_watch(QIO_CHANNEL(ib->sioc), G_IO_IN,
 518                                        input_barrier_event, ib, NULL);
 519}
 520
 521static void input_barrier_instance_finalize(Object *obj)
 522{
 523    InputBarrier *ib = INPUT_BARRIER(obj);
 524
 525    if (ib->ioc_tag) {
 526        g_source_remove(ib->ioc_tag);
 527        ib->ioc_tag = 0;
 528    }
 529
 530    if (ib->sioc) {
 531        qio_channel_close(QIO_CHANNEL(ib->sioc), NULL);
 532        object_unref(OBJECT(ib->sioc));
 533    }
 534    g_free(ib->name);
 535    g_free(ib->saddr.u.inet.host);
 536    g_free(ib->saddr.u.inet.port);
 537}
 538
 539static char *input_barrier_get_name(Object *obj, Error **errp)
 540{
 541    InputBarrier *ib = INPUT_BARRIER(obj);
 542
 543    return g_strdup(ib->name);
 544}
 545
 546static void input_barrier_set_name(Object *obj, const char *value,
 547                                  Error **errp)
 548{
 549    InputBarrier *ib = INPUT_BARRIER(obj);
 550
 551    if (ib->name) {
 552        error_setg(errp, "name property already set");
 553        return;
 554    }
 555    ib->name = g_strdup(value);
 556}
 557
 558static char *input_barrier_get_server(Object *obj, Error **errp)
 559{
 560    InputBarrier *ib = INPUT_BARRIER(obj);
 561
 562    return g_strdup(ib->saddr.u.inet.host);
 563}
 564
 565static void input_barrier_set_server(Object *obj, const char *value,
 566                                     Error **errp)
 567{
 568    InputBarrier *ib = INPUT_BARRIER(obj);
 569
 570    g_free(ib->saddr.u.inet.host);
 571    ib->saddr.u.inet.host = g_strdup(value);
 572}
 573
 574static char *input_barrier_get_port(Object *obj, Error **errp)
 575{
 576    InputBarrier *ib = INPUT_BARRIER(obj);
 577
 578    return g_strdup(ib->saddr.u.inet.port);
 579}
 580
 581static void input_barrier_set_port(Object *obj, const char *value,
 582                                     Error **errp)
 583{
 584    InputBarrier *ib = INPUT_BARRIER(obj);
 585
 586    g_free(ib->saddr.u.inet.port);
 587    ib->saddr.u.inet.port = g_strdup(value);
 588}
 589
 590static void input_barrier_set_x_origin(Object *obj, const char *value,
 591                                       Error **errp)
 592{
 593    InputBarrier *ib = INPUT_BARRIER(obj);
 594    int result, err;
 595
 596    err = qemu_strtoi(value, NULL, 0, &result);
 597    if (err < 0 || result < 0 || result > SHRT_MAX) {
 598        error_setg(errp,
 599                   "x-origin property must be in the range [0..%d]", SHRT_MAX);
 600        return;
 601    }
 602    ib->x_origin = result;
 603}
 604
 605static char *input_barrier_get_x_origin(Object *obj, Error **errp)
 606{
 607    InputBarrier *ib = INPUT_BARRIER(obj);
 608
 609    return g_strdup_printf("%d", ib->x_origin);
 610}
 611
 612static void input_barrier_set_y_origin(Object *obj, const char *value,
 613                                       Error **errp)
 614{
 615    InputBarrier *ib = INPUT_BARRIER(obj);
 616    int result, err;
 617
 618    err = qemu_strtoi(value, NULL, 0, &result);
 619    if (err < 0 || result < 0 || result > SHRT_MAX) {
 620        error_setg(errp,
 621                   "y-origin property must be in the range [0..%d]", SHRT_MAX);
 622        return;
 623    }
 624    ib->y_origin = result;
 625}
 626
 627static char *input_barrier_get_y_origin(Object *obj, Error **errp)
 628{
 629    InputBarrier *ib = INPUT_BARRIER(obj);
 630
 631    return g_strdup_printf("%d", ib->y_origin);
 632}
 633
 634static void input_barrier_set_width(Object *obj, const char *value,
 635                                       Error **errp)
 636{
 637    InputBarrier *ib = INPUT_BARRIER(obj);
 638    int result, err;
 639
 640    err = qemu_strtoi(value, NULL, 0, &result);
 641    if (err < 0 || result < 0 || result > SHRT_MAX) {
 642        error_setg(errp,
 643                   "width property must be in the range [0..%d]", SHRT_MAX);
 644        return;
 645    }
 646    ib->width = result;
 647}
 648
 649static char *input_barrier_get_width(Object *obj, Error **errp)
 650{
 651    InputBarrier *ib = INPUT_BARRIER(obj);
 652
 653    return g_strdup_printf("%d", ib->width);
 654}
 655
 656static void input_barrier_set_height(Object *obj, const char *value,
 657                                       Error **errp)
 658{
 659    InputBarrier *ib = INPUT_BARRIER(obj);
 660    int result, err;
 661
 662    err = qemu_strtoi(value, NULL, 0, &result);
 663    if (err < 0 || result < 0 || result > SHRT_MAX) {
 664        error_setg(errp,
 665                   "height property must be in the range [0..%d]", SHRT_MAX);
 666        return;
 667    }
 668    ib->height = result;
 669}
 670
 671static char *input_barrier_get_height(Object *obj, Error **errp)
 672{
 673    InputBarrier *ib = INPUT_BARRIER(obj);
 674
 675    return g_strdup_printf("%d", ib->height);
 676}
 677
 678static void input_barrier_instance_init(Object *obj)
 679{
 680    InputBarrier *ib = INPUT_BARRIER(obj);
 681
 682    /* always use generic keymaps */
 683    if (keyboard_layout && !kbd_layout) {
 684        /* We use X11 key id, so use VNC name2keysym */
 685        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
 686                                          &error_fatal);
 687    }
 688
 689    ib->saddr.type = SOCKET_ADDRESS_TYPE_INET;
 690    ib->saddr.u.inet.host = g_strdup("localhost");
 691    ib->saddr.u.inet.port = g_strdup("24800");
 692
 693    ib->x_origin = 0;
 694    ib->y_origin = 0;
 695    ib->width = 1920;
 696    ib->height = 1080;
 697}
 698
 699static void input_barrier_class_init(ObjectClass *oc, void *data)
 700{
 701    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 702
 703    ucc->complete = input_barrier_complete;
 704
 705    object_class_property_add_str(oc, "name",
 706                                  input_barrier_get_name,
 707                                  input_barrier_set_name);
 708    object_class_property_add_str(oc, "server",
 709                                  input_barrier_get_server,
 710                                  input_barrier_set_server);
 711    object_class_property_add_str(oc, "port",
 712                                  input_barrier_get_port,
 713                                  input_barrier_set_port);
 714    object_class_property_add_str(oc, "x-origin",
 715                                  input_barrier_get_x_origin,
 716                                  input_barrier_set_x_origin);
 717    object_class_property_add_str(oc, "y-origin",
 718                                  input_barrier_get_y_origin,
 719                                  input_barrier_set_y_origin);
 720    object_class_property_add_str(oc, "width",
 721                                  input_barrier_get_width,
 722                                  input_barrier_set_width);
 723    object_class_property_add_str(oc, "height",
 724                                  input_barrier_get_height,
 725                                  input_barrier_set_height);
 726}
 727
 728static const TypeInfo input_barrier_info = {
 729    .name = TYPE_INPUT_BARRIER,
 730    .parent = TYPE_OBJECT,
 731    .class_init = input_barrier_class_init,
 732    .instance_size = sizeof(InputBarrier),
 733    .instance_init = input_barrier_instance_init,
 734    .instance_finalize = input_barrier_instance_finalize,
 735    .interfaces = (InterfaceInfo[]) {
 736        { TYPE_USER_CREATABLE },
 737        { }
 738    }
 739};
 740
 741static void register_types(void)
 742{
 743    type_register_static(&input_barrier_info);
 744}
 745
 746type_init(register_types);
 747