2
0

input-barrier.c 22 KB

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