input-barrier.c 22 KB

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