Wayland++ 1.0.0
C++ Bindings for Wayland
proxy_wrapper.cpp
1/*
2 * Copyright (c) 2017-2019, Philipp Kerling
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
35#include <iostream>
36#include <thread>
37#include <unistd.h>
38#include <cstdint>
39
40#include <wayland-client.hpp>
41
42using namespace wayland;
43
44class binder
45{
46private:
47 display_t display;
48
49 void bind(bool safe)
50 {
51 registry_t registry;
52 seat_t seat;
53
54 auto queue = display.create_queue();
55 if(safe)
56 {
57 auto display_wrapper = display.proxy_create_wrapper();
58 display_wrapper.set_queue(queue);
59 registry = display_wrapper.get_registry();
60 }
61 else
62 {
63 registry = display.get_registry();
64 // This is the race: registry will be set to the default queue for a very
65 // short while between get_registry() and set_queue() - events dispatched
66 // in between get stuck in the default queue and ultimately lost.
67 registry.set_queue(queue);
68 }
69
70 registry.on_global() = [&seat, &registry](std::uint32_t name, const std::string& interface, std::uint32_t version)
71 {
72 if(interface == seat_t::interface_name)
73 registry.bind(name, seat, version);
74 };
75 display.roundtrip_queue(queue);
76 if(!seat)
77 throw std::runtime_error("Did NOT get seat interface - thread-safety issue!");
78
79 // Now pretend that again another part of the application wants to use the
80 // seat and get the keyboard from it
81 // Note that it would not be necessary to do this in this example, but
82 // this code is useful for testing proxy wrappers with normal interface
83 // objects (display_t is special)
84 auto queue2 = display.create_queue();
85 if(safe)
86 {
87 seat = seat.proxy_create_wrapper();
88 }
89 seat.set_queue(queue2);
90 keyboard_t kbd = seat.get_keyboard();
91 bool have_keymap = false;
92 kbd.on_keymap() = [&have_keymap](keyboard_keymap_format /*unused*/, int fd, std::uint32_t /*unused*/)
93 {
94 close(fd);
95 have_keymap = true;
96 };
97 display.roundtrip_queue(queue2);
98 if(!have_keymap)
99 {
100 throw std::runtime_error("Did NOT get keymap - thread-safety issue!");
101 }
102 }
103
104 std::thread bind_thread(bool safe)
105 {
106 return std::thread{std::bind(&binder::bind, this, safe)};
107 }
108
109public:
110 binder() = default;
111 binder(const binder&) = delete;
112 binder(binder&&) noexcept = delete;
113 ~binder() noexcept = default;
114 binder& operator=(const binder&) = delete;
115 binder& operator=(binder&&) noexcept = delete;
116
117 void run(int thread_count, int round_count, bool safe)
118 {
119 std::atomic<bool> stop{false};
120 std::cout << "Using " << thread_count << " threads, safe: " << safe << std::endl;
121 for(int round = 0; round < round_count; round++)
122 {
123 if(round % 100 == 0)
124 {
125 std::cout << "Round " << round << "/" << round_count << std::endl;
126 }
127 std::vector<std::thread> threads;
128 threads.reserve(thread_count);
129 for(int i = 0; i < thread_count; i++)
130 {
131 threads.emplace_back(bind_thread(safe));
132 }
133 for(auto& thread : threads)
134 {
135 thread.join();
136 }
137 }
138 stop = true;
139 }
140};
141
142int main(int argc, char** argv)
143{
144 if(argc != 4)
145 {
146 std::cerr << "Usage: " << argv[0] << " <thread count> <run count> <use safe mechanism?>" << std::endl;
147 return -1;
148 }
149 binder b;
150 b.run(std::stoi(argv[1]), std::stoi(argv[2]), std::stoi(argv[3]));
151 return 0;
152}
Represents a connection to the compositor and acts as a proxy to the display singleton object.
display_t proxy_create_wrapper()
create proxy wrapper for this display
event_queue_t create_queue() const
Create a new event queue for this display.
int roundtrip_queue(const event_queue_t &queue) const
Block until all pending request are processed by the server.
registry_t get_registry()
get global registry object
std::function< void(keyboard_keymap_format, int, uint32_t)> & on_keymap()
keyboard mapping
void set_queue(event_queue_t queue)
Assign a proxy to an event queue.
global registry object
std::function< void(uint32_t, std::string, uint32_t)> & on_global()
announce global object
proxy_t bind(uint32_t name, proxy_t &interface, uint32_t version)
bind an object to the display
group of input devices
keyboard_t get_keyboard()
return keyboard object