Wayland++  0.2.6
C++ Bindings for Wayland
shm2.cpp
1 // Build with: g++ shm2.cpp -std=c++11 `pkg-config --cflags --libs wayland-client++ wayland-client-extra++ wayland-cursor++` -lrt -o shm2
2 
3 #include <stdexcept>
4 #include <iostream>
5 #include <array>
6 #include <memory>
7 #include <sstream>
8 #include <ctime>
9 #include <algorithm>
10 #include <chrono>
11 
12 #include <wayland-client.hpp>
13 #include <wayland-client-protocol-extra.hpp>
14 #include <linux/input.h>
15 #include <wayland-cursor.hpp>
16 
17 #include <sys/mman.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 
22 using namespace wayland;
23 
24 // example Wayland client
25 class example
26 {
27 private:
28  // global objects
29  display_t display;
30  registry_t registry;
31  compositor_t compositor;
32  shell_t shell;
33  xdg_wm_base_t xdg_wm_base;
34  seat_t seat;
35  shm_t shm;
36 
37  // local objects
38  surface_t surface;
39  shell_surface_t shell_surface;
40  xdg_surface_t xdg_surface;
41  xdg_toplevel_t xdg_toplevel;
42  pointer_t pointer;
43  keyboard_t keyboard;
44  callback_t frame_cb;
45  cursor_image_t cursor_image;
46  buffer_t cursor_buffer;
47  surface_t cursor_surface;
48 
49  // shared memory
50  std::string name;
51  int fd = 0;
52  void *mem = nullptr;
53  buffer_t buffer[2];
54  int cur_buf;
55 
56  bool running;
57  bool has_pointer;
58  bool has_keyboard;
59 
60  unsigned int count;
61  std::chrono::time_point<std::chrono::steady_clock> tstart;
62 
63  void draw(uint32_t serial = 0)
64  {
65  if(serial == 0)
66  {
67  std::fill_n(static_cast<uint32_t*>(mem)+cur_buf*320*240, 320*240, 0xffffff);
68  surface.attach(buffer[cur_buf], 0, 0);
69  surface.damage(0, 0, 320, 240);
70  if(!cur_buf)
71  cur_buf = 1;
72  else
73  cur_buf = 0;
74  tstart = std::chrono::steady_clock::now();
75  count = 0;
76  }
77 
78  // schedule next draw
79  frame_cb = surface.frame();
80  frame_cb.on_done() = [this] (uint32_t serial) { this->draw(serial); };
81  surface.commit();
82 
83  // measure fps
84  auto now = std::chrono::steady_clock::now();
85  auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - tstart).count();
86  if(diff >= 1000)
87  {
88  std::cout << count << std::endl;
89  tstart = now;
90  count = 0;
91  }
92  count++;
93  }
94 
95 public:
96  example()
97  {
98  // retrieve global objects
99  registry = display.get_registry();
100  registry.on_global() = [&] (uint32_t name, std::string interface, uint32_t version)
101  {
102  if(interface == compositor_t::interface_name)
103  registry.bind(name, compositor, version);
104  else if(interface == shell_t::interface_name)
105  registry.bind(name, shell, version);
106  else if(interface == xdg_wm_base_t::interface_name)
107  registry.bind(name, xdg_wm_base, version);
108  else if(interface == seat_t::interface_name)
109  registry.bind(name, seat, version);
110  else if(interface == shm_t::interface_name)
111  registry.bind(name, shm, version);
112  };
113  display.roundtrip();
114 
115  seat.on_capabilities() = [&] (seat_capability capability)
116  {
117  has_keyboard = capability & seat_capability::keyboard;
118  has_pointer = capability & seat_capability::pointer;
119  };
120 
121  // create a surface
122  surface = compositor.create_surface();
123 
124  // create a shell surface
125  if(xdg_wm_base)
126  {
127  xdg_wm_base.on_ping() = [&] (uint32_t serial) { xdg_wm_base.pong(serial); };
128  xdg_surface = xdg_wm_base.get_xdg_surface(surface);
129  xdg_surface.on_configure() = [&] (uint32_t serial) { xdg_surface.ack_configure(serial); };
130  xdg_toplevel = xdg_surface.get_toplevel();
131  xdg_toplevel.set_title("Window");
132  xdg_toplevel.on_close() = [&] () { running = false; };
133  }
134  else
135  {
136  shell_surface = shell.get_shell_surface(surface);
137  shell_surface.on_ping() = [&] (uint32_t serial) { shell_surface.pong(serial); };
138  shell_surface.set_title("Window");
139  shell_surface.set_toplevel();
140  }
141  surface.commit();
142 
143  display.roundtrip();
144 
145  // Get input devices
146  if(!has_keyboard)
147  throw std::runtime_error("No keyboard found.");
148  if(!has_pointer)
149  throw std::runtime_error("No pointer found.");
150 
151  pointer = seat.get_pointer();
152  keyboard = seat.get_keyboard();
153 
154  // create random filename
155  std::stringstream ss;
156  std::srand(std::time(0));
157  ss << '/' << std::rand();
158  name = ss.str();
159 
160  // open shared memory file
161  fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
162  if(fd < 0)
163  throw std::runtime_error("shm_open failed.");
164 
165  // set size
166  if(ftruncate(fd, 2*320*240*4) < 0)
167  throw std::runtime_error("ftruncate failed.");
168 
169  // map memory
170  mem = mmap(NULL, 2*320*240*4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
171  if(mem == MAP_FAILED)
172  throw std::runtime_error("mmap failed.");
173 
174  // create shared memory
175  auto pool = shm.create_pool(fd, 2*320*240*4);
176  for(unsigned int c = 0; c < 2; c++)
177  buffer[c] = pool.create_buffer(c*320*240*4, 320, 240, 320*4, shm_format::argb8888);
178  cur_buf = 0;
179 
180  // load cursor theme
181  cursor_theme_t cursor_theme = cursor_theme_t("default", 16, shm);
182  cursor_t cursor = cursor_theme.get_cursor("cross");
183  cursor_image = cursor.image(0);
184  cursor_buffer = cursor_image.get_buffer();
185 
186  // create cursor surface
187  cursor_surface = compositor.create_surface();
188 
189  // draw cursor
190  pointer.on_enter() = [&] (uint32_t serial, surface_t, int32_t, int32_t)
191  {
192  cursor_surface.attach(cursor_buffer, 0, 0);
193  cursor_surface.damage(0, 0, cursor_image.width(), cursor_image.height());
194  cursor_surface.commit();
195  pointer.set_cursor(serial, cursor_surface, 0, 0);
196  };
197 
198  // window movement
199  pointer.on_button() = [&] (uint32_t serial, uint32_t time, uint32_t button, pointer_button_state state)
200  {
201  if(button == BTN_LEFT && state == pointer_button_state::pressed)
202  {
203  if(xdg_toplevel)
204  xdg_toplevel.move(seat, serial);
205  else
206  shell_surface.move(seat, serial);
207  }
208  };
209 
210  // press 'q' to exit
211  keyboard.on_key() = [&] (uint32_t, uint32_t, uint32_t key, keyboard_key_state state)
212  {
213  if(key == KEY_Q && state == keyboard_key_state::pressed)
214  running = false;
215  };
216 
217  // draw stuff
218  draw();
219  }
220 
221  ~example()
222  {
223  // close shared memory
224  munmap(mem, 2*320*240*4);
225  close(fd);
226  shm_unlink(name.c_str());
227  }
228 
229  void run()
230  {
231  // event loop
232  running = true;
233  while(running)
234  display.dispatch();
235  }
236 };
237 
238 int main()
239 {
240  example e;
241  e.run();
242  return 0;
243 }
wayland::xdg_wm_base_t::pong
void pong(uint32_t serial)
respond to a ping event
Definition: wayland-client-protocol-extra.cpp:968
wayland::surface_t::frame
callback_t frame()
request a frame throttling hint
Definition: wayland-client-protocol.cpp:2633
wayland::display_t
Represents a connection to the compositor and acts as a proxy to the display singleton object.
Definition: wayland-client.hpp:463
wayland::xdg_wm_base_t::get_xdg_surface
xdg_surface_t get_xdg_surface(surface_t surface)
create a shell surface from a surface
Definition: wayland-client-protocol-extra.cpp:962
wayland::pointer_t::on_button
std::function< void(uint32_t, uint32_t, uint32_t, pointer_button_state)> & on_button()
pointer button event
Definition: wayland-client-protocol.cpp:2890
wayland::display_t::dispatch
int dispatch()
Process incoming events.
wayland::display_t::get_registry
registry_t get_registry()
get global registry object
wayland::pointer_t::on_enter
std::function< void(uint32_t, surface_t, double, double)> & on_enter()
enter event
Definition: wayland-client-protocol.cpp:2875
wayland::shm_t::create_pool
shm_pool_t create_pool(int fd, int32_t size)
create a shm pool
Definition: wayland-client-protocol.cpp:1840
wayland::shell_t
create desktop-style surfaces
Definition: wayland-client-protocol.hpp:1419
wayland::shell_surface_t::pong
void pong(uint32_t serial)
respond to a ping event
Definition: wayland-client-protocol.cpp:2476
wayland::pointer_t::set_cursor
void set_cursor(uint32_t serial, surface_t surface, int32_t hotspot_x, int32_t hotspot_y)
set the pointer surface
Definition: wayland-client-protocol.cpp:2861
wayland::callback_t::on_done
std::function< void(uint32_t)> & on_done()
done event
Definition: wayland-client-protocol.cpp:1641
wayland::xdg_surface_t
desktop user interface surface base interface
Definition: wayland-client-protocol-extra.hpp:959
wayland::buffer_t
content for a wl_surface
Definition: wayland-client-protocol.hpp:602
wayland::shm_t
shared memory support
Definition: wayland-client-protocol.hpp:391
wayland::shm_pool_t::create_buffer
buffer_t create_buffer(int32_t offset, int32_t width, int32_t height, int32_t stride, shm_format format)
create a buffer from the pool
Definition: wayland-client-protocol.cpp:1775
wayland::surface_t::commit
void commit()
commit pending surface state
Definition: wayland-client-protocol.cpp:2649
wayland::keyboard_t::on_key
std::function< void(uint32_t, uint32_t, uint32_t, keyboard_key_state)> & on_key()
key event
Definition: wayland-client-protocol.cpp:3033
wayland::shell_surface_t::set_title
void set_title(std::string title)
set surface title
Definition: wayland-client-protocol.cpp:2516
wayland::surface_t::attach
void attach(buffer_t buffer, int32_t x, int32_t y)
set the surface contents
Definition: wayland-client-protocol.cpp:2623
wayland::surface_t
an onscreen surface
Definition: wayland-client-protocol.hpp:1898
wayland::seat_capability::pointer
static const detail::bitfield< 3, 12 > pointer
the seat has pointer devices
Definition: wayland-client-protocol.hpp:2485
wayland::xdg_surface_t::on_configure
std::function< void(uint32_t)> & on_configure()
suggest a surface change
Definition: wayland-client-protocol-extra.cpp:1161
wayland::surface_t::damage
void damage(int32_t x, int32_t y, int32_t width, int32_t height)
mark part of the surface damaged
Definition: wayland-client-protocol.cpp:2628
wayland::seat_capability
seat capability bitmask
Definition: wayland-client-protocol.hpp:2478
wayland::xdg_toplevel_t::on_close
std::function< void()> & on_close()
surface wants to be closed
Definition: wayland-client-protocol-extra.cpp:1300
wayland::shell_surface_t
desktop-style metadata interface
Definition: wayland-client-protocol.hpp:1485
wayland::xdg_toplevel_t::set_title
void set_title(std::string title)
set surface title
Definition: wayland-client-protocol-extra.cpp:1235
wayland::xdg_surface_t::get_toplevel
xdg_toplevel_t get_toplevel()
assign the xdg_toplevel surface role
Definition: wayland-client-protocol-extra.cpp:1139
wayland::shell_surface_t::move
void move(seat_t seat, uint32_t serial)
start an interactive move
Definition: wayland-client-protocol.cpp:2481
wayland::xdg_toplevel_t::move
void move(seat_t seat, uint32_t serial)
start an interactive move
Definition: wayland-client-protocol-extra.cpp:1250
wayland::xdg_toplevel_t
toplevel surface
Definition: wayland-client-protocol-extra.hpp:1143
wayland::registry_t
global registry object
Definition: wayland-client-protocol.hpp:130
wayland::registry_t::bind
proxy_t bind(uint32_t name, proxy_t &interface, uint32_t version)
bind an object to the display
Definition: wayland-client-protocol.cpp:1560
wayland::seat_t
group of input devices
Definition: wayland-client-protocol.hpp:2334
wayland::compositor_t::create_surface
surface_t create_surface()
create new surface
Definition: wayland-client-protocol.cpp:1707
wayland::shell_t::get_shell_surface
shell_surface_t get_shell_surface(surface_t surface)
create a shell surface from a surface
Definition: wayland-client-protocol.cpp:2415
wayland::display_t::roundtrip
int roundtrip()
Block until all pending request are processed by the server.
wayland::shell_surface_t::on_ping
std::function< void(uint32_t)> & on_ping()
ping client
Definition: wayland-client-protocol.cpp:2526
wayland::seat_t::get_pointer
pointer_t get_pointer()
return pointer object
Definition: wayland-client-protocol.cpp:2756
wayland::compositor_t
the compositor singleton
Definition: wayland-client-protocol.hpp:251
wayland::xdg_surface_t::ack_configure
void ack_configure(uint32_t serial)
ack a configure event
Definition: wayland-client-protocol-extra.cpp:1156
wayland::xdg_wm_base_t
create desktop-style surfaces
Definition: wayland-client-protocol-extra.hpp:564
wayland::xdg_wm_base_t::on_ping
std::function< void(uint32_t)> & on_ping()
check if the client is alive
Definition: wayland-client-protocol-extra.cpp:973
wayland::seat_t::get_keyboard
keyboard_t get_keyboard()
return keyboard object
Definition: wayland-client-protocol.cpp:2762
wayland::callback_t
callback object
Definition: wayland-client-protocol.hpp:210
wayland::shell_surface_t::set_toplevel
void set_toplevel()
make the surface a toplevel surface
Definition: wayland-client-protocol.cpp:2491
wayland::registry_t::on_global
std::function< void(uint32_t, std::string, uint32_t)> & on_global()
announce global object
Definition: wayland-client-protocol.cpp:1567
wayland::seat_t::on_capabilities
std::function< void(seat_capability)> & on_capabilities()
seat capabilities changed
Definition: wayland-client-protocol.cpp:2783
wayland::seat_capability::keyboard
static const detail::bitfield< 3, 12 > keyboard
the seat has one or more keyboards
Definition: wayland-client-protocol.hpp:2487
wayland::keyboard_t
keyboard input device
Definition: wayland-client-protocol.hpp:2896
wayland-client.hpp
wayland::pointer_t
pointer input device
Definition: wayland-client-protocol.hpp:2505