logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

Writing-a-wayland-compositor-part-2.md (6657B)


  1. ---
  2. date: 2018-02-22
  3. title: "Writing a Wayland Compositor, Part 2: Rigging up the server"
  4. layout: post
  5. tags: [wayland, wlroots, instructional]
  6. ---
  7. This is the second in a series of articles on the subject of writing a Wayland
  8. compositor from scratch using [wlroots](https://github.com/swaywm/wlroots).
  9. Check out [the first article](/2018/02/17/Writing-a-Wayland-compositor-1.html)
  10. if you haven't already. Last time, we ended up with an application which fired
  11. up a wlroots backend, enumerated output devices, and drew some pretty colors on
  12. the screen. Today, we're going to start accepting Wayland client connections,
  13. though we aren't going to be doing much with them yet.
  14. The commit that this article dissects is
  15. [b45c651](https://github.com/SirCmpwn/mcwayland/commit/b45c651).
  16. A quick aside on the nature of these blog posts: it's going to take *a lot* of
  17. these articles to flesh out our compositor. I'm going to be publishing these
  18. more frequently than usual, probably 1-2 per week, and continue posting my usual
  19. articles at the typical rate. Okay? Cool.
  20. So we've started up the backend and we're rendering something interesting, but
  21. we still aren't running a Wayland server -- Wayland clients aren't connecting to
  22. our application. Adding this is actually quite easy:
  23. ```diff
  24. @@ -113,12 +113,18 @@ int main(int argc, char **argv) {
  25. server.new_output.notify = new_output_notify;
  26. wl_signal_add(&server.backend->events.new_output, &server.new_output);
  27. + const char *socket = wl_display_add_socket_auto(server.wl_display);
  28. + assert(socket);
  29. +
  30. if (!wlr_backend_start(server.backend)) {
  31. fprintf(stderr, "Failed to start backend\n");
  32. wl_display_destroy(server.wl_display);
  33. return 1;
  34. }
  35. + printf("Running compositor on wayland display '%s'\n", socket);
  36. + setenv("WAYLAND_DISPLAY", socket, true);
  37. +
  38. wl_display_run(server.wl_display);
  39. wl_display_destroy(server.wl_display);
  40. return 0;
  41. ```
  42. That's it! If you run McWayface again, it'll print something like this:
  43. ```
  44. Running compositor on wayland display 'wayland-1'
  45. ```
  46. [Weston](https://cgit.freedesktop.org/wayland/weston/), the Wayland reference
  47. compositor, includes a number of simple reference clients. We can use
  48. `weston-info` to connect to our server and list the **globals**:
  49. ```
  50. $ WAYLAND_DISPLAY=wayland-1 weston-info
  51. interface: 'wl_drm', version: 2, name: 1
  52. ```
  53. If you recall from my [Introduction to
  54. Wayland](/2017/06/10/Introduction-to-Wayland.html), the Wayland server exports a
  55. list of **globals** to clients via the Wayland registry. These globals provide
  56. interfaces the client can utilize to interact with the server. We get `wl_drm`
  57. for free with wlroots, but we have not actually wired up anything useful yet.
  58. Wlroots provides many "types", of which the majority are implementations of
  59. Wayland global interfaces like this.
  60. Some of the wlroots implementations require some rigging from you, but several
  61. of them just take care of themselves. Rigging these up is easy:
  62. ```diff
  63. printf("Running compositor on wayland display '%s'\n", socket);
  64. setenv("WAYLAND_DISPLAY", socket, true);
  65. +
  66. + wl_display_init_shm(server.wl_display);
  67. + wlr_gamma_control_manager_create(server.wl_display);
  68. + wlr_screenshooter_create(server.wl_display);
  69. + wlr_primary_selection_device_manager_create(server.wl_display);
  70. + wlr_idle_create(server.wl_display);
  71. wl_display_run(server.wl_display);
  72. wl_display_destroy(server.wl_display);
  73. ```
  74. Note that some of these interfaces are not necessarily ones that you typically
  75. would want to expose to all Wayland clients - screenshooter, for example, is
  76. something that should be secured. We'll get to security in a later article. For
  77. now, if we run `weston-info` again, we'll see a few more globals have appeared:
  78. ```
  79. $ WAYLAND_DISPLAY=wayland-1 weston-info
  80. interface: 'wl_shm', version: 1, name: 3
  81. formats: XRGB8888 ARGB8888
  82. interface: 'wl_drm', version: 2, name: 1
  83. interface: 'gamma_control_manager', version: 1, name: 2
  84. interface: 'orbital_screenshooter', version: 1, name: 3
  85. interface: 'gtk_primary_selection_device_manager', version: 1, name: 4
  86. interface: 'org_kde_kwin_idle', version: 1, name: 5
  87. ```
  88. You'll find that wlroots implements a variety of protocols from a variety of
  89. sources - here we see protocols from Orbital, GTK, and KDE represented. Wlroots
  90. includes an example client for the orbital screenshooter - we can use it now to
  91. take a screenshot of our compositor:
  92. ```
  93. $ WAYLAND_DISPLAY=wayland-1 ./examples/screenshot
  94. cannot set buffer size
  95. ```
  96. Ah, this is a problem - you may have noticed that we don't have any wl_output
  97. globals, which the screenshooter client relies on to figure out the resolution
  98. of the screenshot buffer. We can add these, too:
  99. ```diff
  100. @@ -95,6 +99,8 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
  101. wl_signal_add(&wlr_output->events.destroy, &output->destroy);
  102. output->frame.notify = output_frame_notify;
  103. wl_signal_add(&wlr_output->events.frame, &output->frame);
  104. +
  105. + wlr_output_create_global(wlr_output);
  106. }
  107. ```
  108. Running `weston-info` again will give us some info about our outputs now:
  109. ```
  110. $ WAYLAND_DISPLAY=wayland-1 weston-info
  111. interface: 'wl_drm', version: 2, name: 1
  112. interface: 'wl_output', version: 3, name: 2
  113. x: 0, y: 0, scale: 1,
  114. physical_width: 0 mm, physical_height: 0 mm,
  115. make: 'wayland', model: 'wayland',
  116. subpixel_orientation: unknown, output_transform: normal,
  117. mode:
  118. width: 952 px, height: 521 px, refresh: 0.000 Hz,
  119. flags: current
  120. interface: 'wl_shm', version: 1, name: 3
  121. formats: XRGB8888 ARGB8888
  122. interface: 'gamma_control_manager', version: 1, name: 4
  123. interface: 'orbital_screenshooter', version: 1, name: 5
  124. interface: 'gtk_primary_selection_device_manager', version: 1, name: 6
  125. interface: 'org_kde_kwin_idle', version: 1, name: 7
  126. ```
  127. Now we can take that screenshot! Give it a shot (heh)!
  128. We're getting close to the good stuff now. The next article is going to
  129. introduce the concept of **surfaces**, and we will use them to render our first
  130. window. If you had any trouble with this article, please reach out to me at
  131. [sir@cmpwn.com](mailto:sir@cmpwn.com) or to the wlroots team at
  132. [#sway-devel](http://webchat.freenode.net/?channels=sway-devel&uio=d4).
  133. <p style="float: right">
  134. Next &mdash;
  135. <a href="/2018/02/28/Writing-a-wayland-compositor-part-3.html">
  136. Part 3: Rendering a window
  137. </a>
  138. </p>
  139. <p>
  140. Previous &mdash;
  141. <a href="/2018/02/17/Writing-a-Wayland-compositor-1.html">
  142. Part 1: Hello wlroots
  143. </a>
  144. </p>