SDL  2.0
SDL_waylandwindow.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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 #include "SDL_hints.h"
35 
36 static void
37 handle_ping(void *data, struct wl_shell_surface *shell_surface,
38  uint32_t serial)
39 {
40  wl_shell_surface_pong(shell_surface, serial);
41 }
42 
43 static void
44 handle_configure(void *data, struct wl_shell_surface *shell_surface,
46 {
47  SDL_WindowData *wind = (SDL_WindowData *)data;
48  SDL_Window *window = wind->sdlwindow;
49  struct wl_region *region;
50 
51  /* wl_shell_surface spec states that this is a suggestion.
52  Ignore if less than or greater than max/min size. */
53 
54  if (width == 0 || height == 0) {
55  return;
56  }
57 
58  if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
59  if ((window->flags & SDL_WINDOW_RESIZABLE)) {
60  if (window->max_w > 0) {
61  width = SDL_min(width, window->max_w);
62  }
63  width = SDL_max(width, window->min_w);
64 
65  if (window->max_h > 0) {
66  height = SDL_min(height, window->max_h);
67  }
68  height = SDL_max(height, window->min_h);
69  } else {
70  return;
71  }
72  }
73 
74  if (width == window->w && height == window->h) {
75  return;
76  }
77 
78  window->w = width;
79  window->h = height;
80  WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
81 
83  wl_region_add(region, 0, 0, window->w, window->h);
85  wl_region_destroy(region);
86  SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
87 }
88 
89 static void
90 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
91 {
92 }
93 
94 static const struct wl_shell_surface_listener shell_surface_listener = {
95  handle_ping,
96  handle_configure,
97  handle_popup_done
98 };
99 
100 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
101 static void
102 handle_onscreen_visibility(void *data,
103  struct qt_extended_surface *qt_extended_surface, int32_t visible)
104 {
105 }
106 
107 static void
108 handle_set_generic_property(void *data,
109  struct qt_extended_surface *qt_extended_surface, const char *name,
110  struct wl_array *value)
111 {
112 }
113 
114 static void
115 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
116 {
117  SDL_WindowData *window = (SDL_WindowData *)data;
119 }
120 
121 static const struct qt_extended_surface_listener extended_surface_listener = {
122  handle_onscreen_visibility,
123  handle_set_generic_property,
124  handle_close,
125 };
126 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
127 
128 SDL_bool
130 {
131  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
132  const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
133  (((Uint32) info->version.minor) * 10000) +
134  (((Uint32) info->version.patch)));
135 
136  /* Before 2.0.6, it was possible to build an SDL with Wayland support
137  (SDL_SysWMinfo will be large enough to hold Wayland info), but build
138  your app against SDL headers that didn't have Wayland support
139  (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
140  to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
141  overflow memory on the stack or heap. To protect against this, we've
142  padded out the struct unconditionally in the headers and Wayland will
143  just return an error for older apps using this function. Those apps
144  will need to be recompiled against newer headers or not use Wayland,
145  maybe by forcing SDL_VIDEODRIVER=x11. */
146  if (version < 2000006) {
148  SDL_SetError("Version must be 2.0.6 or newer");
149  return SDL_FALSE;
150  }
151 
152  info->info.wl.display = data->waylandData->display;
153  info->info.wl.surface = data->surface;
154  info->info.wl.shell_surface = data->shell_surface;
156 
157  return SDL_TRUE;
158 }
159 
160 int
162 {
163  return 0; /* just succeed, the real work is done elsewhere. */
164 }
165 
166 void Wayland_ShowWindow(_THIS, SDL_Window *window)
167 {
168  SDL_WindowData *wind = window->driverdata;
169 
170  if (window->flags & SDL_WINDOW_FULLSCREEN)
173  0, (struct wl_output *)window->fullscreen_mode.driverdata);
174  else
176 
177  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
178 }
179 
180 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
181 static void SDLCALL
182 QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
183  const char *oldValue, const char *newValue)
184 {
185  struct qt_extended_surface *qt_extended_surface = userdata;
186 
187  if (name == NULL) {
188  return;
189  }
190 
191  if (strcmp(name, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION) == 0) {
192  int32_t orientation = QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION;
193 
194  if (newValue != NULL) {
195  if (strcmp(newValue, "portrait") == 0) {
196  orientation = QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION;
197  } else if (strcmp(newValue, "landscape") == 0) {
198  orientation = QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION;
199  } else if (strcmp(newValue, "inverted-portrait") == 0) {
200  orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION;
201  } else if (strcmp(newValue, "inverted-landscape") == 0) {
202  orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION;
203  }
204  }
205 
206  qt_extended_surface_set_content_orientation(qt_extended_surface, orientation);
207  } else if (strcmp(name, SDL_HINT_QTWAYLAND_WINDOW_FLAGS) == 0) {
208  uint32_t flags = 0;
209 
210  if (newValue != NULL) {
211  char *tmp = strdup(newValue);
212  char *saveptr = NULL;
213 
214  char *flag = strtok_r(tmp, " ", &saveptr);
215  while (flag) {
216  if (strcmp(flag, "OverridesSystemGestures") == 0) {
217  flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES;
218  } else if (strcmp(flag, "StaysOnTop") == 0) {
219  flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP;
220  } else if (strcmp(flag, "BypassWindowManager") == 0) {
221  // See https://github.com/qtproject/qtwayland/commit/fb4267103d
222  flags |= 4 /* QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER */;
223  }
224 
225  flag = strtok_r(NULL, " ", &saveptr);
226  }
227 
228  free(tmp);
229  }
230 
231  qt_extended_surface_set_window_flags(qt_extended_surface, flags);
232  }
233 }
234 
235 static void QtExtendedSurface_Subscribe(struct qt_extended_surface *surface, const char *name)
236 {
237  SDL_AddHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
238 }
239 
240 static void QtExtendedSurface_Unsubscribe(struct qt_extended_surface *surface, const char *name)
241 {
242  SDL_DelHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
243 }
244 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
245 
246 void
248  SDL_VideoDisplay * _display, SDL_bool fullscreen)
249 {
250  SDL_WindowData *wind = window->driverdata;
251 
252  if (fullscreen)
255  0, (struct wl_output *)_display->driverdata);
256  else
258 
259  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
260 }
261 
262 void
264 {
265  SDL_WindowData *wind = window->driverdata;
266 
268 
269  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
270 }
271 
272 void
274 {
275  SDL_WindowData *wind = window->driverdata;
276 
278 
279  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
280 }
281 
283 {
285  SDL_VideoData *c;
286  struct wl_region *region;
287 
288  data = calloc(1, sizeof *data);
289  if (data == NULL)
290  return SDL_OutOfMemory();
291 
292  c = _this->driverdata;
293  window->driverdata = data;
294 
295  if (!(window->flags & SDL_WINDOW_OPENGL)) {
297  window->flags |= SDL_WINDOW_OPENGL;
298  }
299 
300  if (window->x == SDL_WINDOWPOS_UNDEFINED) {
301  window->x = 0;
302  }
303  if (window->y == SDL_WINDOWPOS_UNDEFINED) {
304  window->y = 0;
305  }
306 
307  data->waylandData = c;
308  data->sdlwindow = window;
309 
310  data->surface =
312  wl_surface_set_user_data(data->surface, data);
314  data->surface);
316 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
317  if (c->surface_extension) {
318  data->extended_surface = qt_surface_extension_get_extended_surface(
319  c->surface_extension, data->surface);
320 
321  QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
322  QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
323  }
324 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
325 
326  data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
327  window->w, window->h);
328 
329  /* Create the GLES window surface */
330  data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
331 
332  if (data->egl_surface == EGL_NO_SURFACE) {
333  return SDL_SetError("failed to create a window surface");
334  }
335 
336  if (data->shell_surface) {
339  &shell_surface_listener, data);
340  }
341 
342 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
343  if (data->extended_surface) {
344  qt_extended_surface_set_user_data(data->extended_surface, data);
345  qt_extended_surface_add_listener(data->extended_surface,
346  &extended_surface_listener, data);
347  }
348 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
349 
351  wl_region_add(region, 0, 0, window->w, window->h);
352  wl_surface_set_opaque_region(data->surface, region);
353  wl_region_destroy(region);
354 
355  if (c->relative_mouse_mode) {
357  }
358 
359  WAYLAND_wl_display_flush(c->display);
360 
361  return 0;
362 }
363 
364 void Wayland_SetWindowSize(_THIS, SDL_Window * window)
365 {
366  SDL_VideoData *data = _this->driverdata;
367  SDL_WindowData *wind = window->driverdata;
368  struct wl_region *region;
369 
370  WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
371 
373  wl_region_add(region, 0, 0, window->w, window->h);
374  wl_surface_set_opaque_region(wind->surface, region);
375  wl_region_destroy(region);
376 }
377 
379 {
380  SDL_WindowData *wind = window->driverdata;
381 
382  if (window->title != NULL) {
384  }
385 
386  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
387 }
388 
390 {
391  SDL_VideoData *data = _this->driverdata;
392  SDL_WindowData *wind = window->driverdata;
393 
394  if (data) {
395  SDL_EGL_DestroySurface(_this, wind->egl_surface);
396  WAYLAND_wl_egl_window_destroy(wind->egl_window);
397 
398  if (wind->shell_surface)
400 
401 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
402  if (wind->extended_surface) {
403  QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
404  QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
405  qt_extended_surface_destroy(wind->extended_surface);
406  }
407 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
409 
410  SDL_free(wind);
411  WAYLAND_wl_display_flush(data->display);
412  }
413  window->driverdata = NULL;
414 }
415 
416 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
417 
418 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_HINT_QTWAYLAND_WINDOW_FLAGS
Flags to set on QtWayland windows to integrate with the native window manager.
Definition: SDL_hints.h:488
void Wayland_SetWindowSize(_THIS, SDL_Window *window)
#define SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION
A variable describing the content orientation on QtWayland-based platforms.
Definition: SDL_hints.h:477
static void wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data)
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
void Wayland_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *_display, SDL_bool fullscreen)
SDL_DisplayMode fullscreen_mode
Definition: SDL_sysvideo.h:89
static struct wl_region * wl_compositor_create_region(struct wl_compositor *wl_compositor)
#define EGL_NO_SURFACE
Definition: egl.h:100
signed int int32_t
static void wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
static void wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data)
struct wl_display * display
void Wayland_MaximizeWindow(_THIS, SDL_Window *window)
static void wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
SDL_EventEntry * free
Definition: SDL_events.c:84
EGLSurface surface
Definition: eglext.h:248
SDL_version version
Definition: SDL_syswm.h:196
Uint8 major
Definition: SDL_version.h:53
void Wayland_ShowWindow(_THIS, SDL_Window *window)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
static void wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:197
static void wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
#define SDL_WINDOWPOS_UNDEFINED
Definition: SDL_video.h:128
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
static void wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_GL_LoadLibrary
static void wl_surface_destroy(struct wl_surface *wl_surface)
struct SDL_WaylandInput * input
int Wayland_CreateWindow(_THIS, SDL_Window *window)
static void wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
SDL_Surface * surface
GLuint const GLchar * name
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
EGLNativeWindowType NativeWindowType
Definition: eglplatform.h:112
void Wayland_SetWindowTitle(_THIS, SDL_Window *window)
void Wayland_DestroyWindow(_THIS, SDL_Window *window)
#define _THIS
#define SDL_free
void * driverdata
Definition: SDL_video.h:59
SDL_Window * sdlwindow
struct wl_shell_surface * shell_surface
static void wl_region_destroy(struct wl_region *wl_region)
SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *info)
struct wl_shell * shell
SDL_VideoData * waylandData
const GLubyte * c
GLsizei const GLfloat * value
Uint8 minor
Definition: SDL_version.h:54
char * title
Definition: SDL_sysvideo.h:77
static void wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
static struct wl_shell_surface * wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface)
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
static void wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
SDL_bool
Definition: SDL_stdinc.h:139
unsigned int uint32_t
#define SDL_SetError
GLbitfield flags
struct wl_compositor * compositor
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
void Wayland_RestoreWindow(_THIS, SDL_Window *window)
static struct wl_surface * wl_compositor_create_surface(struct wl_compositor *wl_compositor)
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
The type used to identify a window.
Definition: SDL_sysvideo.h:73
#define SDL_AddHintCallback
#define SDL_DelHintCallback
static void wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
union SDL_SysWMinfo::@18 info
struct SDL_SysWMinfo::@18::@20 wl
void * driverdata
Definition: SDL_sysvideo.h:111
Uint32 flags
Definition: SDL_sysvideo.h:83
static int wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, const struct wl_shell_surface_listener *listener, void *data)
#define SDLCALL
Definition: SDL_internal.h:45
EGLSurface egl_surface
Uint8 patch
Definition: SDL_version.h:55
struct wl_egl_window * egl_window