PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/wayland-20120424/src/wayland-client.c

#
C | 585 lines | 458 code | 104 blank | 23 comment | 59 complexity | 7d8e80a5f85de7443f119f3f45aec1f7 MD5 | raw file
  1. /*
  2. * Copyright Š 2008 Kristian Hřgsberg
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that copyright
  7. * notice and this permission notice appear in supporting documentation, and
  8. * that the name of the copyright holders not be used in advertising or
  9. * publicity pertaining to distribution of the software without specific,
  10. * written prior permission. The copyright holders make no representations
  11. * about the suitability of this software for any purpose. It is provided "as
  12. * is" without express or implied warranty.
  13. *
  14. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  20. * OF THIS SOFTWARE.
  21. */
  22. #include <stdlib.h>
  23. #include <stdint.h>
  24. #include <stddef.h>
  25. #include <stdio.h>
  26. #include <stdbool.h>
  27. #include <errno.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <sys/socket.h>
  31. #include <sys/un.h>
  32. #include <ctype.h>
  33. #include <assert.h>
  34. #include <fcntl.h>
  35. #include <sys/poll.h>
  36. #include "wayland-util.h"
  37. #include "wayland-os.h"
  38. #include "wayland-client.h"
  39. #include "wayland-private.h"
  40. struct wl_global_listener {
  41. wl_display_global_func_t handler;
  42. void *data;
  43. struct wl_list link;
  44. };
  45. struct wl_proxy {
  46. struct wl_object object;
  47. struct wl_display *display;
  48. void *user_data;
  49. };
  50. struct wl_global {
  51. uint32_t id;
  52. char *interface;
  53. uint32_t version;
  54. struct wl_list link;
  55. };
  56. struct wl_display {
  57. struct wl_proxy proxy;
  58. struct wl_connection *connection;
  59. int fd;
  60. uint32_t mask;
  61. struct wl_map objects;
  62. struct wl_list global_listener_list;
  63. struct wl_list global_list;
  64. wl_display_update_func_t update;
  65. void *update_data;
  66. wl_display_global_func_t global_handler;
  67. void *global_handler_data;
  68. };
  69. static int wl_debug = 0;
  70. static int
  71. connection_update(struct wl_connection *connection,
  72. uint32_t mask, void *data)
  73. {
  74. struct wl_display *display = data;
  75. display->mask = mask;
  76. if (display->update)
  77. return display->update(display->mask,
  78. display->update_data);
  79. return 0;
  80. }
  81. WL_EXPORT struct wl_global_listener *
  82. wl_display_add_global_listener(struct wl_display *display,
  83. wl_display_global_func_t handler, void *data)
  84. {
  85. struct wl_global_listener *listener;
  86. struct wl_global *global;
  87. listener = malloc(sizeof *listener);
  88. if (listener == NULL)
  89. return NULL;
  90. listener->handler = handler;
  91. listener->data = data;
  92. wl_list_insert(display->global_listener_list.prev, &listener->link);
  93. wl_list_for_each(global, &display->global_list, link)
  94. (*listener->handler)(display, global->id, global->interface,
  95. global->version, listener->data);
  96. return listener;
  97. }
  98. WL_EXPORT void
  99. wl_display_remove_global_listener(struct wl_display *display,
  100. struct wl_global_listener *listener)
  101. {
  102. wl_list_remove(&listener->link);
  103. free(listener);
  104. }
  105. WL_EXPORT struct wl_proxy *
  106. wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
  107. {
  108. struct wl_proxy *proxy;
  109. struct wl_display *display = factory->display;
  110. proxy = malloc(sizeof *proxy);
  111. if (proxy == NULL)
  112. return NULL;
  113. proxy->object.interface = interface;
  114. proxy->object.implementation = NULL;
  115. proxy->object.id = wl_map_insert_new(&display->objects,
  116. WL_MAP_CLIENT_SIDE, proxy);
  117. proxy->display = display;
  118. return proxy;
  119. }
  120. WL_EXPORT struct wl_proxy *
  121. wl_proxy_create_for_id(struct wl_proxy *factory,
  122. uint32_t id, const struct wl_interface *interface)
  123. {
  124. struct wl_proxy *proxy;
  125. struct wl_display *display = factory->display;
  126. proxy = malloc(sizeof *proxy);
  127. if (proxy == NULL)
  128. return NULL;
  129. proxy->object.interface = interface;
  130. proxy->object.implementation = NULL;
  131. proxy->object.id = id;
  132. proxy->display = display;
  133. wl_map_insert_at(&display->objects, id, proxy);
  134. return proxy;
  135. }
  136. WL_EXPORT void
  137. wl_proxy_destroy(struct wl_proxy *proxy)
  138. {
  139. if (proxy->object.id < WL_SERVER_ID_START)
  140. wl_map_insert_at(&proxy->display->objects,
  141. proxy->object.id, WL_ZOMBIE_OBJECT);
  142. else
  143. wl_map_insert_at(&proxy->display->objects,
  144. proxy->object.id, NULL);
  145. free(proxy);
  146. }
  147. WL_EXPORT int
  148. wl_proxy_add_listener(struct wl_proxy *proxy,
  149. void (**implementation)(void), void *data)
  150. {
  151. if (proxy->object.implementation) {
  152. fprintf(stderr, "proxy already has listener\n");
  153. return -1;
  154. }
  155. proxy->object.implementation = implementation;
  156. proxy->user_data = data;
  157. return 0;
  158. }
  159. WL_EXPORT void
  160. wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
  161. {
  162. struct wl_closure closure;
  163. va_list ap;
  164. int ret;
  165. va_start(ap, opcode);
  166. ret = wl_closure_vmarshal(&closure, &proxy->object, opcode, ap,
  167. &proxy->object.interface->methods[opcode]);
  168. va_end(ap);
  169. if (ret) {
  170. fprintf(stderr, "Error marshalling request\n");
  171. abort();
  172. }
  173. if (wl_closure_send(&closure, proxy->display->connection)) {
  174. fprintf(stderr, "Error sending request: %m\n");
  175. abort();
  176. }
  177. if (wl_debug)
  178. wl_closure_print(&closure, &proxy->object, true);
  179. wl_closure_destroy(&closure);
  180. }
  181. /* Can't do this, there may be more than one instance of an
  182. * interface... */
  183. WL_EXPORT uint32_t
  184. wl_display_get_global(struct wl_display *display,
  185. const char *interface, uint32_t version)
  186. {
  187. struct wl_global *global;
  188. wl_list_for_each(global, &display->global_list, link)
  189. if (strcmp(interface, global->interface) == 0 &&
  190. version <= global->version)
  191. return global->id;
  192. return 0;
  193. }
  194. static void
  195. display_handle_error(void *data,
  196. struct wl_display *display, struct wl_object *object,
  197. uint32_t code, const char *message)
  198. {
  199. fprintf(stderr, "%s@%d: error %d: %s\n",
  200. object->interface->name, object->id, code, message);
  201. abort();
  202. }
  203. static void
  204. display_handle_global(void *data,
  205. struct wl_display *display,
  206. uint32_t id, const char *interface, uint32_t version)
  207. {
  208. struct wl_global_listener *listener;
  209. struct wl_global *global;
  210. global = malloc(sizeof *global);
  211. global->id = id;
  212. global->interface = strdup(interface);
  213. global->version = version;
  214. wl_list_insert(display->global_list.prev, &global->link);
  215. wl_list_for_each(listener, &display->global_listener_list, link)
  216. (*listener->handler)(display,
  217. id, interface, version, listener->data);
  218. }
  219. static void
  220. wl_global_destroy(struct wl_global *global)
  221. {
  222. wl_list_remove(&global->link);
  223. free(global->interface);
  224. free(global);
  225. }
  226. static void
  227. display_handle_global_remove(void *data,
  228. struct wl_display *display, uint32_t id)
  229. {
  230. struct wl_global *global;
  231. wl_list_for_each(global, &display->global_list, link)
  232. if (global->id == id) {
  233. wl_global_destroy(global);
  234. break;
  235. }
  236. }
  237. static void
  238. display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)
  239. {
  240. struct wl_proxy *proxy;
  241. proxy = wl_map_lookup(&display->objects, id);
  242. if (proxy != WL_ZOMBIE_OBJECT)
  243. fprintf(stderr, "server sent delete_id for live object\n");
  244. else
  245. wl_map_remove(&display->objects, id);
  246. }
  247. static const struct wl_display_listener display_listener = {
  248. display_handle_error,
  249. display_handle_global,
  250. display_handle_global_remove,
  251. display_handle_delete_id
  252. };
  253. static int
  254. connect_to_socket(struct wl_display *display, const char *name)
  255. {
  256. struct sockaddr_un addr;
  257. socklen_t size;
  258. const char *runtime_dir;
  259. size_t name_size;
  260. display->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
  261. if (display->fd < 0)
  262. return -1;
  263. runtime_dir = getenv("XDG_RUNTIME_DIR");
  264. if (runtime_dir == NULL) {
  265. runtime_dir = ".";
  266. fprintf(stderr,
  267. "XDG_RUNTIME_DIR not set, falling back to %s\n",
  268. runtime_dir);
  269. }
  270. if (name == NULL)
  271. name = getenv("WAYLAND_DISPLAY");
  272. if (name == NULL)
  273. name = "wayland-0";
  274. memset(&addr, 0, sizeof addr);
  275. addr.sun_family = AF_LOCAL;
  276. name_size =
  277. snprintf(addr.sun_path, sizeof addr.sun_path,
  278. "%s/%s", runtime_dir, name) + 1;
  279. size = offsetof (struct sockaddr_un, sun_path) + name_size;
  280. if (connect(display->fd, (struct sockaddr *) &addr, size) < 0) {
  281. close(display->fd);
  282. return -1;
  283. }
  284. return 0;
  285. }
  286. WL_EXPORT struct wl_display *
  287. wl_display_connect(const char *name)
  288. {
  289. struct wl_display *display;
  290. const char *debug;
  291. char *connection, *end;
  292. int flags;
  293. debug = getenv("WAYLAND_DEBUG");
  294. if (debug)
  295. wl_debug = 1;
  296. display = malloc(sizeof *display);
  297. if (display == NULL)
  298. return NULL;
  299. memset(display, 0, sizeof *display);
  300. connection = getenv("WAYLAND_SOCKET");
  301. if (connection) {
  302. display->fd = strtol(connection, &end, 0);
  303. if (*end != '\0') {
  304. free(display);
  305. return NULL;
  306. }
  307. flags = fcntl(display->fd, F_GETFD);
  308. if (flags != -1)
  309. fcntl(display->fd, F_SETFD, flags | FD_CLOEXEC);
  310. unsetenv("WAYLAND_SOCKET");
  311. } else if (connect_to_socket(display, name) < 0) {
  312. free(display);
  313. return NULL;
  314. }
  315. wl_map_init(&display->objects);
  316. wl_list_init(&display->global_listener_list);
  317. wl_list_init(&display->global_list);
  318. wl_map_insert_new(&display->objects, WL_MAP_CLIENT_SIDE, NULL);
  319. display->proxy.object.interface = &wl_display_interface;
  320. display->proxy.object.id =
  321. wl_map_insert_new(&display->objects,
  322. WL_MAP_CLIENT_SIDE, display);
  323. display->proxy.display = display;
  324. display->proxy.object.implementation = (void(**)(void)) &display_listener;
  325. display->proxy.user_data = display;
  326. display->connection = wl_connection_create(display->fd,
  327. connection_update, display);
  328. if (display->connection == NULL) {
  329. wl_map_release(&display->objects);
  330. close(display->fd);
  331. free(display);
  332. return NULL;
  333. }
  334. return display;
  335. }
  336. WL_EXPORT void
  337. wl_display_disconnect(struct wl_display *display)
  338. {
  339. struct wl_global *global, *gnext;
  340. struct wl_global_listener *listener, *lnext;
  341. wl_connection_destroy(display->connection);
  342. wl_map_release(&display->objects);
  343. wl_list_for_each_safe(global, gnext,
  344. &display->global_list, link)
  345. wl_global_destroy(global);
  346. wl_list_for_each_safe(listener, lnext,
  347. &display->global_listener_list, link)
  348. free(listener);
  349. close(display->fd);
  350. free(display);
  351. }
  352. WL_EXPORT int
  353. wl_display_get_fd(struct wl_display *display,
  354. wl_display_update_func_t update, void *data)
  355. {
  356. display->update = update;
  357. display->update_data = data;
  358. if (display->update)
  359. display->update(display->mask,
  360. display->update_data);
  361. return display->fd;
  362. }
  363. static void
  364. sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
  365. {
  366. int *done = data;
  367. *done = 1;
  368. wl_callback_destroy(callback);
  369. }
  370. static const struct wl_callback_listener sync_listener = {
  371. sync_callback
  372. };
  373. WL_EXPORT void
  374. wl_display_roundtrip(struct wl_display *display)
  375. {
  376. struct wl_callback *callback;
  377. int done;
  378. done = 0;
  379. callback = wl_display_sync(display);
  380. wl_callback_add_listener(callback, &sync_listener, &done);
  381. wl_display_flush(display);
  382. while (!done)
  383. wl_display_iterate(display, WL_DISPLAY_READABLE);
  384. }
  385. static void
  386. handle_event(struct wl_display *display,
  387. uint32_t id, uint32_t opcode, uint32_t size)
  388. {
  389. struct wl_proxy *proxy;
  390. struct wl_closure closure;
  391. const struct wl_message *message;
  392. int ret;
  393. proxy = wl_map_lookup(&display->objects, id);
  394. if (proxy == WL_ZOMBIE_OBJECT) {
  395. wl_connection_consume(display->connection, size);
  396. return;
  397. } else if (proxy == NULL || proxy->object.implementation == NULL) {
  398. wl_connection_consume(display->connection, size);
  399. return;
  400. }
  401. message = &proxy->object.interface->events[opcode];
  402. ret = wl_connection_demarshal(display->connection, &closure,
  403. size, &display->objects, message);
  404. if (ret) {
  405. fprintf(stderr, "Error demarshalling event\n");
  406. abort();
  407. }
  408. if (wl_debug)
  409. wl_closure_print(&closure, &proxy->object, false);
  410. wl_closure_invoke(&closure, &proxy->object,
  411. proxy->object.implementation[opcode],
  412. proxy->user_data);
  413. wl_closure_destroy(&closure);
  414. }
  415. WL_EXPORT void
  416. wl_display_iterate(struct wl_display *display, uint32_t mask)
  417. {
  418. uint32_t p[2], object;
  419. int len, opcode, size;
  420. mask &= display->mask;
  421. if (mask == 0) {
  422. fprintf(stderr,
  423. "wl_display_iterate called with unsolicited flags");
  424. return;
  425. }
  426. len = wl_connection_data(display->connection, mask);
  427. while (len > 0) {
  428. if ((size_t) len < sizeof p)
  429. break;
  430. wl_connection_copy(display->connection, p, sizeof p);
  431. object = p[0];
  432. opcode = p[1] & 0xffff;
  433. size = p[1] >> 16;
  434. if (len < size)
  435. break;
  436. handle_event(display, object, opcode, size);
  437. len -= size;
  438. }
  439. if (len < 0) {
  440. fprintf(stderr, "read error: %m\n");
  441. exit(EXIT_FAILURE);
  442. }
  443. }
  444. WL_EXPORT void
  445. wl_display_flush(struct wl_display *display)
  446. {
  447. while (display->mask & WL_DISPLAY_WRITABLE)
  448. wl_display_iterate (display, WL_DISPLAY_WRITABLE);
  449. }
  450. WL_EXPORT void *
  451. wl_display_bind(struct wl_display *display,
  452. uint32_t name, const struct wl_interface *interface)
  453. {
  454. struct wl_proxy *proxy;
  455. proxy = wl_proxy_create(&display->proxy, interface);
  456. if (proxy == NULL)
  457. return NULL;
  458. wl_proxy_marshal(&display->proxy, WL_DISPLAY_BIND,
  459. name, interface->name, interface->version, proxy);
  460. return proxy;
  461. }
  462. WL_EXPORT struct wl_callback *
  463. wl_display_sync(struct wl_display *display)
  464. {
  465. struct wl_proxy *proxy;
  466. proxy = wl_proxy_create(&display->proxy, &wl_callback_interface);
  467. if (!proxy)
  468. return NULL;
  469. wl_proxy_marshal(&display->proxy, WL_DISPLAY_SYNC, proxy);
  470. return (struct wl_callback *) proxy;
  471. }
  472. WL_EXPORT void
  473. wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
  474. {
  475. proxy->user_data = user_data;
  476. }
  477. WL_EXPORT void *
  478. wl_proxy_get_user_data(struct wl_proxy *proxy)
  479. {
  480. return proxy->user_data;
  481. }