cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

input-barrier.c (22180B)


      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);