1 /* wl-clipboard
2 *
3 * Copyright © 2019 Sergey Bugaev <bugaevc@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "types/registry.h"
20 #include "types/seat.h"
21 #include "types/shell.h"
22 #include "types/device-manager.h"
23 #include "includes/shell-protocols.h"
24 #include "includes/selection-protocols.h"
25 #include "util/misc.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29
30 #define BIND(interface_name, known_version) \
31 if (strcmp(interface, #interface_name) == 0) { \
32 self->interface_name = wl_registry_bind( \
33 wl_registry, \
34 name, \
35 &interface_name ## _interface, \
36 known_version \
37 ); \
38 }
39
wl_registry_global_handler(void * data,struct wl_registry * wl_registry,uint32_t name,const char * interface,uint32_t version)40 static void wl_registry_global_handler(
41 void *data,
42 struct wl_registry *wl_registry,
43 uint32_t name,
44 const char *interface,
45 uint32_t version
46 ) {
47 struct registry *self = (struct registry *) data;
48
49 BIND(wl_compositor, 2)
50 BIND(wl_shm, 1)
51
52 /* Shells */
53
54 BIND(wl_shell, 1)
55
56 #ifdef HAVE_XDG_SHELL
57 BIND(xdg_wm_base, 1)
58 #endif
59
60 /* Device managers */
61
62 BIND(wl_data_device_manager, 1)
63
64 #ifdef HAVE_GTK_PRIMARY_SELECTION
65 BIND(gtk_primary_selection_device_manager, 1)
66 #endif
67
68 #ifdef HAVE_WP_PRIMARY_SELECTION
69 BIND(zwp_primary_selection_device_manager_v1, 1)
70 #endif
71
72 #ifdef HAVE_WLR_DATA_CONTROL
73 BIND(zwlr_data_control_manager_v1, version > 2 ? 2 : version)
74 #endif
75
76 if (strcmp(interface, "wl_seat") == 0) {
77 struct seat *seat = calloc(1, sizeof(struct seat));
78 seat->proxy = wl_registry_bind(
79 wl_registry,
80 name,
81 &wl_seat_interface,
82 2
83 );
84 seat_init(seat);
85 struct seat **ptr = wl_array_add(&self->seats, sizeof(struct seat *));
86 *ptr = seat;
87 }
88 }
89
wl_registry_global_remove_handler(void * data,struct wl_registry * wl_registry,uint32_t name)90 static void wl_registry_global_remove_handler(
91 void *data,
92 struct wl_registry *wl_registry,
93 uint32_t name
94 ) {}
95
96 static const struct wl_registry_listener wl_registry_listener = {
97 .global = wl_registry_global_handler,
98 .global_remove = wl_registry_global_remove_handler
99 };
100
registry_init(struct registry * self)101 void registry_init(struct registry *self) {
102 self->proxy = wl_display_get_registry(self->wl_display);
103 wl_registry_add_listener(self->proxy, &wl_registry_listener, self);
104 }
105
registry_find_shell(struct registry * self)106 struct shell *registry_find_shell(struct registry *self) {
107 struct shell *shell = calloc(1, sizeof(struct shell));
108
109 if (self->wl_shell != NULL) {
110 shell->proxy = (struct wl_proxy *) self->wl_shell;
111 shell_init_wl_shell(shell);
112 return shell;
113 }
114
115 #ifdef HAVE_XDG_SHELL
116 if (self->xdg_wm_base != NULL) {
117 shell->proxy = (struct wl_proxy *) self->xdg_wm_base;
118 shell_init_xdg_shell(shell);
119 return shell;
120 }
121 #endif
122
123 free(shell);
124 return NULL;
125 }
126
127 #define TRY(type) \
128 if (self->type != NULL) { \
129 device_manager->proxy = (struct wl_proxy *) self->type; \
130 device_manager_init_ ## type(device_manager); \
131 return device_manager; \
132 }
133
registry_find_device_manager(struct registry * self,int primary)134 struct device_manager *registry_find_device_manager(
135 struct registry *self,
136 int primary
137 ) {
138 struct device_manager *device_manager
139 = calloc(1, sizeof(struct device_manager));
140 device_manager->wl_display = self->wl_display;
141
142 /* For regular selection, we just look at the two supported
143 * protocols. We prefer wlr-data-control, as it doesn't require
144 * us to use the popup surface hack.
145 */
146
147 if (!primary) {
148 #ifdef HAVE_WLR_DATA_CONTROL
149 TRY(zwlr_data_control_manager_v1)
150 #endif
151 TRY(wl_data_device_manager)
152
153 free(device_manager);
154 return NULL;
155 }
156
157 /* For primary selection, it's a bit more complicated. We also
158 * prefer wlr-data-control, but we don't know in advance whether
159 * the compositor supports primary selection, as unlike with
160 * other protocols here, the mere presence of wlr-data-control
161 * does not imply primary selection support. However, we assume
162 * that if a compositor supports primary selection at all, then
163 * if it supports wlr-data-control v2 it also supports primary
164 * selection over wlr-data-control; which is only reasonable.
165 */
166
167 #ifdef HAVE_WLR_DATA_CONTROL
168 if (self->zwlr_data_control_manager_v1 != NULL) {
169 struct wl_proxy *proxy
170 = (struct wl_proxy *) self->zwlr_data_control_manager_v1;
171 if (wl_proxy_get_version(proxy) >= 2) {
172 device_manager->proxy = proxy;
173 device_manager_init_zwlr_data_control_manager_v1(device_manager);
174 return device_manager;
175 }
176 }
177 #endif
178
179 #ifdef HAVE_WP_PRIMARY_SELECTION
180 TRY(zwp_primary_selection_device_manager_v1)
181 #endif
182
183 #ifdef HAVE_GTK_PRIMARY_SELECTION
184 TRY(gtk_primary_selection_device_manager)
185 #endif
186
187 free(device_manager);
188 return NULL;
189 }
190
registry_find_seat(struct registry * self,const char * name)191 struct seat *registry_find_seat(
192 struct registry *self,
193 const char *name
194 ) {
195 /* Ensure we get all the seat info */
196 wl_display_roundtrip(self->wl_display);
197
198 struct seat **ptr;
199 wl_array_for_each(ptr, &self->seats) {
200 struct seat *seat = *ptr;
201 if (name == NULL || strcmp(seat->name, name) == 0) {
202 return seat;
203 }
204 }
205 return NULL;
206 }
207