1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #include "../../SDL_internal.h"
23
24 #if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
25
26 #include "../SDL_sysvideo.h"
27 #include "../../events/SDL_windowevents_c.h"
28 #include "../SDL_egl_c.h"
29 #include "SDL_waylandevents_c.h"
30 #include "SDL_waylandwindow.h"
31 #include "SDL_waylandvideo.h"
32 #include "SDL_waylandtouch.h"
33 #include "SDL_waylanddyn.h"
34
35 static void
handle_ping(void * data,struct wl_shell_surface * shell_surface,uint32_t serial)36 handle_ping(void *data, struct wl_shell_surface *shell_surface,
37 uint32_t serial)
38 {
39 wl_shell_surface_pong(shell_surface, serial);
40 }
41
42 static void
handle_configure(void * data,struct wl_shell_surface * shell_surface,uint32_t edges,int32_t width,int32_t height)43 handle_configure(void *data, struct wl_shell_surface *shell_surface,
44 uint32_t edges, int32_t width, int32_t height)
45 {
46 SDL_WindowData *wind = (SDL_WindowData *)data;
47 SDL_Window *window = wind->sdlwindow;
48 struct wl_region *region;
49
50 /* wl_shell_surface spec states that this is a suggestion.
51 Ignore if less than or greater than max/min size. */
52
53 if (width == 0 || height == 0) {
54 return;
55 }
56
57 if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
58 if ((window->flags & SDL_WINDOW_RESIZABLE)) {
59 if (window->max_w > 0) {
60 width = SDL_min(width, window->max_w);
61 }
62 width = SDL_max(width, window->min_w);
63
64 if (window->max_h > 0) {
65 height = SDL_min(height, window->max_h);
66 }
67 height = SDL_max(height, window->min_h);
68 } else {
69 return;
70 }
71 }
72
73 if (width == window->w && height == window->h) {
74 return;
75 }
76
77 window->w = width;
78 window->h = height;
79 WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
80
81 region = wl_compositor_create_region(wind->waylandData->compositor);
82 wl_region_add(region, 0, 0, window->w, window->h);
83 wl_surface_set_opaque_region(wind->surface, region);
84 wl_region_destroy(region);
85 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
86 }
87
88 static void
handle_popup_done(void * data,struct wl_shell_surface * shell_surface)89 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
90 {
91 }
92
93 static const struct wl_shell_surface_listener shell_surface_listener = {
94 handle_ping,
95 handle_configure,
96 handle_popup_done
97 };
98
99 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
100 static void
handle_onscreen_visibility(void * data,struct qt_extended_surface * qt_extended_surface,int32_t visible)101 handle_onscreen_visibility(void *data,
102 struct qt_extended_surface *qt_extended_surface, int32_t visible)
103 {
104 }
105
106 static void
handle_set_generic_property(void * data,struct qt_extended_surface * qt_extended_surface,const char * name,struct wl_array * value)107 handle_set_generic_property(void *data,
108 struct qt_extended_surface *qt_extended_surface, const char *name,
109 struct wl_array *value)
110 {
111 }
112
113 static void
handle_close(void * data,struct qt_extended_surface * qt_extended_surface)114 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
115 {
116 SDL_WindowData *window = (SDL_WindowData *)data;
117 SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
118 }
119
120 static const struct qt_extended_surface_listener extended_surface_listener = {
121 handle_onscreen_visibility,
122 handle_set_generic_property,
123 handle_close,
124 };
125 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
126
127 SDL_bool
Wayland_GetWindowWMInfo(_THIS,SDL_Window * window,SDL_SysWMinfo * info)128 Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
129 {
130 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
131
132 info->info.wl.display = data->waylandData->display;
133 info->info.wl.surface = data->surface;
134 info->info.wl.shell_surface = data->shell_surface;
135 info->subsystem = SDL_SYSWM_WAYLAND;
136
137 return SDL_TRUE;
138 }
139
140 int
Wayland_SetWindowHitTest(SDL_Window * window,SDL_bool enabled)141 Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
142 {
143 return 0; /* just succeed, the real work is done elsewhere. */
144 }
145
Wayland_ShowWindow(_THIS,SDL_Window * window)146 void Wayland_ShowWindow(_THIS, SDL_Window *window)
147 {
148 SDL_WindowData *wind = window->driverdata;
149
150 if (window->flags & SDL_WINDOW_FULLSCREEN)
151 wl_shell_surface_set_fullscreen(wind->shell_surface,
152 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
153 0, (struct wl_output *)window->fullscreen_mode.driverdata);
154 else
155 wl_shell_surface_set_toplevel(wind->shell_surface);
156
157 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
158 }
159
160 void
Wayland_SetWindowFullscreen(_THIS,SDL_Window * window,SDL_VideoDisplay * _display,SDL_bool fullscreen)161 Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
162 SDL_VideoDisplay * _display, SDL_bool fullscreen)
163 {
164 SDL_WindowData *wind = window->driverdata;
165
166 if (fullscreen)
167 wl_shell_surface_set_fullscreen(wind->shell_surface,
168 WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
169 0, (struct wl_output *)_display->driverdata);
170 else
171 wl_shell_surface_set_toplevel(wind->shell_surface);
172
173 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
174 }
175
176 void
Wayland_RestoreWindow(_THIS,SDL_Window * window)177 Wayland_RestoreWindow(_THIS, SDL_Window * window)
178 {
179 SDL_WindowData *wind = window->driverdata;
180
181 wl_shell_surface_set_toplevel(wind->shell_surface);
182
183 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
184 }
185
186 void
Wayland_MaximizeWindow(_THIS,SDL_Window * window)187 Wayland_MaximizeWindow(_THIS, SDL_Window * window)
188 {
189 SDL_WindowData *wind = window->driverdata;
190
191 wl_shell_surface_set_maximized(wind->shell_surface, NULL);
192
193 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
194 }
195
Wayland_CreateWindow(_THIS,SDL_Window * window)196 int Wayland_CreateWindow(_THIS, SDL_Window *window)
197 {
198 SDL_WindowData *data;
199 SDL_VideoData *c;
200 struct wl_region *region;
201
202 data = calloc(1, sizeof *data);
203 if (data == NULL)
204 return SDL_OutOfMemory();
205
206 c = _this->driverdata;
207 window->driverdata = data;
208
209 if (!(window->flags & SDL_WINDOW_OPENGL)) {
210 SDL_GL_LoadLibrary(NULL);
211 window->flags |= SDL_WINDOW_OPENGL;
212 }
213
214 if (window->x == SDL_WINDOWPOS_UNDEFINED) {
215 window->x = 0;
216 }
217 if (window->y == SDL_WINDOWPOS_UNDEFINED) {
218 window->y = 0;
219 }
220
221 data->waylandData = c;
222 data->sdlwindow = window;
223
224 data->surface =
225 wl_compositor_create_surface(c->compositor);
226 wl_surface_set_user_data(data->surface, data);
227 data->shell_surface = wl_shell_get_shell_surface(c->shell,
228 data->surface);
229 wl_shell_surface_set_class (data->shell_surface, c->classname);
230 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
231 if (c->surface_extension) {
232 data->extended_surface = qt_surface_extension_get_extended_surface(
233 c->surface_extension, data->surface);
234 }
235 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
236
237 data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
238 window->w, window->h);
239
240 /* Create the GLES window surface */
241 data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
242
243 if (data->egl_surface == EGL_NO_SURFACE) {
244 return SDL_SetError("failed to create a window surface");
245 }
246
247 if (data->shell_surface) {
248 wl_shell_surface_set_user_data(data->shell_surface, data);
249 wl_shell_surface_add_listener(data->shell_surface,
250 &shell_surface_listener, data);
251 }
252
253 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
254 if (data->extended_surface) {
255 qt_extended_surface_set_user_data(data->extended_surface, data);
256 qt_extended_surface_add_listener(data->extended_surface,
257 &extended_surface_listener, data);
258 }
259 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
260
261 region = wl_compositor_create_region(c->compositor);
262 wl_region_add(region, 0, 0, window->w, window->h);
263 wl_surface_set_opaque_region(data->surface, region);
264 wl_region_destroy(region);
265
266 if (c->relative_mouse_mode) {
267 Wayland_input_lock_pointer(c->input);
268 }
269
270 WAYLAND_wl_display_flush(c->display);
271
272 return 0;
273 }
274
Wayland_SetWindowSize(_THIS,SDL_Window * window)275 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
276 {
277 SDL_VideoData *data = _this->driverdata;
278 SDL_WindowData *wind = window->driverdata;
279 struct wl_region *region;
280
281 WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
282
283 region =wl_compositor_create_region(data->compositor);
284 wl_region_add(region, 0, 0, window->w, window->h);
285 wl_surface_set_opaque_region(wind->surface, region);
286 wl_region_destroy(region);
287 }
288
Wayland_SetWindowTitle(_THIS,SDL_Window * window)289 void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
290 {
291 SDL_WindowData *wind = window->driverdata;
292
293 if (window->title != NULL) {
294 wl_shell_surface_set_title(wind->shell_surface, window->title);
295 }
296
297 WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
298 }
299
Wayland_DestroyWindow(_THIS,SDL_Window * window)300 void Wayland_DestroyWindow(_THIS, SDL_Window *window)
301 {
302 SDL_VideoData *data = _this->driverdata;
303 SDL_WindowData *wind = window->driverdata;
304
305 if (data) {
306 SDL_EGL_DestroySurface(_this, wind->egl_surface);
307 WAYLAND_wl_egl_window_destroy(wind->egl_window);
308
309 if (wind->shell_surface)
310 wl_shell_surface_destroy(wind->shell_surface);
311
312 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
313 if (wind->extended_surface)
314 qt_extended_surface_destroy(wind->extended_surface);
315 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
316 wl_surface_destroy(wind->surface);
317
318 SDL_free(wind);
319 WAYLAND_wl_display_flush(data->display);
320 }
321 window->driverdata = NULL;
322 }
323
324 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
325
326 /* vi: set ts=4 sw=4 expandtab: */
327