SDL  2.0
SDL_waylandwindow.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 
40 
41 static float get_window_scale_factor(SDL_Window *window) {
42  return ((SDL_WindowData*)window->driverdata)->scale_factor;
43 }
44 
45 /* On modern desktops, we probably will use the xdg-shell protocol instead
46  of wl_shell, but wl_shell might be useful on older Wayland installs that
47  don't have the newer protocol, or embedded things that don't have a full
48  window manager. */
49 
50 static void
51 handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
52  uint32_t serial)
53 {
54  wl_shell_surface_pong(shell_surface, serial);
55 }
56 
57 static void
58 handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
60 {
62  SDL_Window *window = wind->sdlwindow;
63 
64  /* wl_shell_surface spec states that this is a suggestion.
65  Ignore if less than or greater than max/min size. */
66 
67  if (width == 0 || height == 0) {
68  return;
69  }
70 
71  if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
72  if ((window->flags & SDL_WINDOW_RESIZABLE)) {
73  if (window->max_w > 0) {
74  width = SDL_min(width, window->max_w);
75  }
76  width = SDL_max(width, window->min_w);
77 
78  if (window->max_h > 0) {
79  height = SDL_min(height, window->max_h);
80  }
81  height = SDL_max(height, window->min_h);
82  } else {
83  return;
84  }
85  }
86 
87  wind->resize.width = width;
88  wind->resize.height = height;
89  wind->resize.pending = SDL_TRUE;
90 
91  if (!(window->flags & SDL_WINDOW_OPENGL)) {
92  Wayland_HandlePendingResize(window); /* OpenGL windows handle this in SwapWindow */
93  }
94 }
95 
96 static void
97 handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
98 {
99 }
100 
101 static const struct wl_shell_surface_listener shell_surface_listener_wl = {
102  handle_ping_wl_shell_surface,
103  handle_configure_wl_shell_surface,
104  handle_popup_done_wl_shell_surface
105 };
106 
107 
108 
109 
110 static void
111 handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
112 {
114  SDL_Window *window = wind->sdlwindow;
115  struct wl_region *region;
116 
118  window->w = 0;
119  window->h = 0;
121  window->w = wind->resize.width;
122  window->h = wind->resize.height;
123 
124  wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
125  if (wind->egl_window) {
126  WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
127  }
128 
129  zxdg_surface_v6_ack_configure(zxdg, serial);
130 
132  wl_region_add(region, 0, 0, window->w, window->h);
133  wl_surface_set_opaque_region(wind->surface, region);
134  wl_region_destroy(region);
135 
137  } else {
138  wind->resize.pending = SDL_TRUE;
139  wind->resize.configure = SDL_TRUE;
140  wind->resize.serial = serial;
141  if (!(window->flags & SDL_WINDOW_OPENGL)) {
142  Wayland_HandlePendingResize(window); /* OpenGL windows handle this in SwapWindow */
143  }
144  }
145 }
146 
147 static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
148  handle_configure_zxdg_shell_surface
149 };
150 
151 
152 static void
153 handle_configure_zxdg_toplevel(void *data,
154  struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
155  int32_t width,
156  int32_t height,
157  struct wl_array *states)
158 {
160  SDL_Window *window = wind->sdlwindow;
161 
163  SDL_bool fullscreen = SDL_FALSE;
164  wl_array_for_each(state, states) {
166  fullscreen = SDL_TRUE;
167  }
168  }
169 
170  if (!fullscreen) {
171  if (width == 0 || height == 0) {
172  width = window->windowed.w;
173  height = window->windowed.h;
174  }
175 
176  /* zxdg_toplevel spec states that this is a suggestion.
177  Ignore if less than or greater than max/min size. */
178 
179  if ((window->flags & SDL_WINDOW_RESIZABLE)) {
180  if (window->max_w > 0) {
181  width = SDL_min(width, window->max_w);
182  }
183  width = SDL_max(width, window->min_w);
184 
185  if (window->max_h > 0) {
186  height = SDL_min(height, window->max_h);
187  }
188  height = SDL_max(height, window->min_h);
189  } else {
190  wind->resize.width = window->w;
191  wind->resize.height = window->h;
192  return;
193  }
194  }
195 
196  if (width == 0 || height == 0) {
197  wind->resize.width = window->w;
198  wind->resize.height = window->h;
199  return;
200  }
201 
202  wind->resize.width = width;
203  wind->resize.height = height;
204 }
205 
206 static void
207 handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
208 {
211 }
212 
213 static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
214  handle_configure_zxdg_toplevel,
215  handle_close_zxdg_toplevel
216 };
217 
218 
219 
220 static void
221 handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial)
222 {
224  SDL_Window *window = wind->sdlwindow;
225  struct wl_region *region;
226 
228  window->w = 0;
229  window->h = 0;
231  window->w = wind->resize.width;
232  window->h = wind->resize.height;
233 
234  wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
235  if (wind->egl_window) {
236  WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
237  }
238 
239  xdg_surface_ack_configure(xdg, serial);
240 
242  wl_region_add(region, 0, 0, window->w, window->h);
243  wl_surface_set_opaque_region(wind->surface, region);
244  wl_region_destroy(region);
245 
247  } else {
248  wind->resize.pending = SDL_TRUE;
249  wind->resize.configure = SDL_TRUE;
250  wind->resize.serial = serial;
251  if (!(window->flags & SDL_WINDOW_OPENGL)) {
252  Wayland_HandlePendingResize(window); /* OpenGL windows handle this in SwapWindow */
253  }
254  }
255 }
256 
257 static const struct xdg_surface_listener shell_surface_listener_xdg = {
258  handle_configure_xdg_shell_surface
259 };
260 
261 
262 static void
263 handle_configure_xdg_toplevel(void *data,
264  struct xdg_toplevel *xdg_toplevel,
265  int32_t width,
266  int32_t height,
267  struct wl_array *states)
268 {
270  SDL_Window *window = wind->sdlwindow;
271 
273  SDL_bool fullscreen = SDL_FALSE;
274  wl_array_for_each(state, states) {
276  fullscreen = SDL_TRUE;
277  }
278  }
279 
280  if (!fullscreen) {
281  if (width == 0 || height == 0) {
282  width = window->windowed.w;
283  height = window->windowed.h;
284  }
285 
286  /* xdg_toplevel spec states that this is a suggestion.
287  Ignore if less than or greater than max/min size. */
288 
289  if ((window->flags & SDL_WINDOW_RESIZABLE)) {
290  if (window->max_w > 0) {
291  width = SDL_min(width, window->max_w);
292  }
293  width = SDL_max(width, window->min_w);
294 
295  if (window->max_h > 0) {
296  height = SDL_min(height, window->max_h);
297  }
298  height = SDL_max(height, window->min_h);
299  } else {
300  wind->resize.width = window->w;
301  wind->resize.height = window->h;
302  return;
303  }
304  }
305 
306  if (width == 0 || height == 0) {
307  wind->resize.width = window->w;
308  wind->resize.height = window->h;
309  return;
310  }
311 
312  wind->resize.width = width;
313  wind->resize.height = height;
314 }
315 
316 static void
317 handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
318 {
321 }
322 
323 static const struct xdg_toplevel_listener toplevel_listener_xdg = {
324  handle_configure_xdg_toplevel,
325  handle_close_xdg_toplevel
326 };
327 
328 
329 
330 
331 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
332 static void
333 handle_onscreen_visibility(void *data,
334  struct qt_extended_surface *qt_extended_surface, int32_t visible)
335 {
336 }
337 
338 static void
339 handle_set_generic_property(void *data,
340  struct qt_extended_surface *qt_extended_surface, const char *name,
341  struct wl_array *value)
342 {
343 }
344 
345 static void
346 handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
347 {
350 }
351 
352 static const struct qt_extended_surface_listener extended_surface_listener = {
353  handle_onscreen_visibility,
354  handle_set_generic_property,
355  handle_close,
356 };
357 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
358 
359 static void
360 update_scale_factor(SDL_WindowData *window) {
361  float old_factor = window->scale_factor, new_factor = 0.0;
362  int i;
363 
364  if (!(window->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
365  return;
366  }
367 
368  if (!window->num_outputs) {
369  new_factor = old_factor;
370  }
371 
372  if (FULLSCREEN_VISIBLE(window->sdlwindow) && window->sdlwindow->fullscreen_mode.driverdata) {
373  new_factor = ((SDL_WaylandOutputData*)(wl_output_get_user_data(window->sdlwindow->fullscreen_mode.driverdata)))->scale_factor;
374  }
375 
376  for (i = 0; i < window->num_outputs; i++) {
377  float factor = ((SDL_WaylandOutputData*)(wl_output_get_user_data(window->outputs[i])))->scale_factor;
378  if (factor > new_factor) {
379  new_factor = factor;
380  }
381  }
382 
383  if (new_factor != old_factor) {
384  /* force the resize event to trigger, as the logical size didn't change */
385  window->resize.width = window->sdlwindow->w;
386  window->resize.height = window->sdlwindow->h;
387  window->resize.scale_factor = new_factor;
388  window->resize.pending = SDL_TRUE;
389  if (!(window->sdlwindow->flags & SDL_WINDOW_OPENGL)) {
390  Wayland_HandlePendingResize(window->sdlwindow); /* OpenGL windows handle this in SwapWindow */
391  }
392  }
393 }
394 
395 static void
396 handle_surface_enter(void *data, struct wl_surface *surface,
397  struct wl_output *output) {
399 
400  window->outputs = SDL_realloc(window->outputs, (window->num_outputs + 1) * sizeof *window->outputs);
401  window->outputs[window->num_outputs++] = output;
402  update_scale_factor(window);
403 }
404 
405 static void
406 handle_surface_leave(void *data, struct wl_surface *surface,
407  struct wl_output *output) {
409  int i;
410 
411  for (i = 0; i < window->num_outputs; i++) {
412  if (window->outputs[i] == output) { /* remove this one */
413  if (i == (window->num_outputs-1)) {
414  window->outputs[i] = NULL;
415  } else {
416  SDL_memmove(&window->outputs[i], &window->outputs[i+1], sizeof (output) * ((window->num_outputs - i) - 1));
417  }
418  window->num_outputs--;
419  i--;
420  }
421  }
422 
423  if (window->num_outputs == 0) {
424  SDL_free(window->outputs);
425  window->outputs = NULL;
426  }
427 
428  update_scale_factor(window);
429 }
430 
431 static const struct wl_surface_listener surface_listener = {
432  handle_surface_enter,
433  handle_surface_leave
434 };
435 
436 SDL_bool
438 {
439  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
440  const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
441  (((Uint32) info->version.minor) * 10000) +
442  (((Uint32) info->version.patch)));
443 
444  /* Before 2.0.6, it was possible to build an SDL with Wayland support
445  (SDL_SysWMinfo will be large enough to hold Wayland info), but build
446  your app against SDL headers that didn't have Wayland support
447  (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
448  to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
449  overflow memory on the stack or heap. To protect against this, we've
450  padded out the struct unconditionally in the headers and Wayland will
451  just return an error for older apps using this function. Those apps
452  will need to be recompiled against newer headers or not use Wayland,
453  maybe by forcing SDL_VIDEODRIVER=x11. */
454  if (version < 2000006) {
456  SDL_SetError("Version must be 2.0.6 or newer");
457  return SDL_FALSE;
458  }
459 
460  info->info.wl.display = data->waylandData->display;
461  info->info.wl.surface = data->surface;
462  info->info.wl.shell_surface = data->shell_surface.wl;
464 
465  return SDL_TRUE;
466 }
467 
468 int
470 {
471  return 0; /* just succeed, the real work is done elsewhere. */
472 }
473 
474 static void
475 SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
476 {
477  const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
478  SDL_WindowData *wind = window->driverdata;
479 
480  if (viddata->shell.xdg) {
481  if (output) {
483  } else {
485  }
486  } else if (viddata->shell.zxdg) {
487  if (output) {
489  } else {
491  }
492  } else {
493  if (output) {
496  0, output);
497  } else {
499  }
500  }
501 
502  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
503 }
504 
506 {
507  struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
508  SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
509 }
510 
511 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
512 static void SDLCALL
513 QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
514  const char *oldValue, const char *newValue)
515 {
516  struct qt_extended_surface *qt_extended_surface = userdata;
517 
518  if (name == NULL) {
519  return;
520  }
521 
522  if (strcmp(name, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION) == 0) {
523  int32_t orientation = QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION;
524 
525  if (newValue != NULL) {
526  if (strcmp(newValue, "portrait") == 0) {
527  orientation = QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION;
528  } else if (strcmp(newValue, "landscape") == 0) {
529  orientation = QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION;
530  } else if (strcmp(newValue, "inverted-portrait") == 0) {
531  orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION;
532  } else if (strcmp(newValue, "inverted-landscape") == 0) {
533  orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION;
534  }
535  }
536 
537  qt_extended_surface_set_content_orientation(qt_extended_surface, orientation);
538  } else if (strcmp(name, SDL_HINT_QTWAYLAND_WINDOW_FLAGS) == 0) {
539  uint32_t flags = 0;
540 
541  if (newValue != NULL) {
542  char *tmp = strdup(newValue);
543  char *saveptr = NULL;
544 
545  char *flag = strtok_r(tmp, " ", &saveptr);
546  while (flag) {
547  if (strcmp(flag, "OverridesSystemGestures") == 0) {
548  flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES;
549  } else if (strcmp(flag, "StaysOnTop") == 0) {
550  flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP;
551  } else if (strcmp(flag, "BypassWindowManager") == 0) {
552  // See https://github.com/qtproject/qtwayland/commit/fb4267103d
553  flags |= 4 /* QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER */;
554  }
555 
556  flag = strtok_r(NULL, " ", &saveptr);
557  }
558 
559  free(tmp);
560  }
561 
562  qt_extended_surface_set_window_flags(qt_extended_surface, flags);
563  }
564 }
565 
566 static void QtExtendedSurface_Subscribe(struct qt_extended_surface *surface, const char *name)
567 {
568  SDL_AddHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
569 }
570 
571 static void QtExtendedSurface_Unsubscribe(struct qt_extended_surface *surface, const char *name)
572 {
573  SDL_DelHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
574 }
575 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
576 
577 void
579  SDL_VideoDisplay * _display, SDL_bool fullscreen)
580 {
581  struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output;
582  SetFullscreen(_this, window, fullscreen ? output : NULL);
583 }
584 
585 void
587 {
588  SDL_WindowData *wind = window->driverdata;
589  const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
590 
591  if (viddata->shell.xdg) {
592  } else if (viddata->shell.zxdg) {
593  } else {
595  }
596 
597  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
598 }
599 
600 void
602 {
603  SDL_WindowData *wind = window->driverdata;
604  const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
605  if ((viddata->decoration_manager) && (wind->server_decoration)) {
608  } else if ((viddata->kwin_server_decoration_manager) && (wind->kwin_server_decoration)) {
611  }
612 }
613 
614 void
616 {
617  SDL_WindowData *wind = window->driverdata;
619 
620  if (viddata->shell.xdg) {
622  } else if (viddata->shell.zxdg) {
624  } else {
626  }
627 
628  WAYLAND_wl_display_flush( viddata->display );
629 }
630 
631 void
633 {
635 
636  if (grabbed)
638  else
640 }
641 
643 {
645  SDL_VideoData *c;
646  struct wl_region *region;
647 
648  data = SDL_calloc(1, sizeof *data);
649  if (data == NULL)
650  return SDL_OutOfMemory();
651 
652  c = _this->driverdata;
653  window->driverdata = data;
654 
655  if (!(window->flags & SDL_WINDOW_VULKAN)) {
656  if (!(window->flags & SDL_WINDOW_OPENGL)) {
658  window->flags |= SDL_WINDOW_OPENGL;
659  }
660  }
661 
662  if (window->x == SDL_WINDOWPOS_UNDEFINED) {
663  window->x = 0;
664  }
665  if (window->y == SDL_WINDOWPOS_UNDEFINED) {
666  window->y = 0;
667  }
668 
669  data->waylandData = c;
670  data->sdlwindow = window;
671 
672  data->scale_factor = 1.0;
673 
674  if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
675  int i;
676  for (i=0; i < SDL_GetVideoDevice()->num_displays; i++) {
677  float scale = ((SDL_WaylandOutputData*)SDL_GetVideoDevice()->displays[i].driverdata)->scale_factor;
678  if (scale > data->scale_factor) {
679  data->scale_factor = scale;
680  }
681  }
682  }
683 
684  data->resize.pending = SDL_FALSE;
685  data->resize.width = window->w;
686  data->resize.height = window->h;
687  data->resize.scale_factor = data->scale_factor;
688 
689  data->outputs = NULL;
690  data->num_outputs = 0;
691 
692  data->surface =
693  wl_compositor_create_surface(c->compositor);
694  wl_surface_add_listener(data->surface, &surface_listener, data);
695 
696  if (c->shell.xdg) {
697  data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface);
698  /* !!! FIXME: add popup role */
699  data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
700  xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
701  xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
702  } else if (c->shell.zxdg) {
703  data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
704  /* !!! FIXME: add popup role */
705  data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
706  zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
707  zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
708  } else {
709  data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
710  wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
711  }
712 
713 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
714  if (c->surface_extension) {
715  data->extended_surface = qt_surface_extension_get_extended_surface(
716  c->surface_extension, data->surface);
717 
718  QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
719  QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
720  }
721 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
722 
723  if (window->flags & SDL_WINDOW_OPENGL) {
724  data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
725  window->w * data->scale_factor, window->h * data->scale_factor);
726 
727  /* Create the GLES window surface */
728  data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
729 
730  if (data->egl_surface == EGL_NO_SURFACE) {
731  return SDL_SetError("failed to create an EGL window surface");
732  }
733  }
734 
735  if (c->shell.xdg) {
736  if (data->shell_surface.xdg.surface) {
737  xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
738  xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data);
739  }
740  } else if (c->shell.zxdg) {
741  if (data->shell_surface.zxdg.surface) {
742  zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
743  zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
744  }
745  } else {
746  if (data->shell_surface.wl) {
747  wl_shell_surface_set_user_data(data->shell_surface.wl, data);
748  wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
749  }
750  }
751 
752 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
753  if (data->extended_surface) {
754  qt_extended_surface_set_user_data(data->extended_surface, data);
755  qt_extended_surface_add_listener(data->extended_surface,
756  &extended_surface_listener, data);
757  }
758 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
759 
760  if (c->decoration_manager && c->shell.xdg && data->shell_surface.xdg.surface) {
761  data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel);
762  if (data->server_decoration) {
763  const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
765  zxdg_toplevel_decoration_v1_set_mode(data->server_decoration, mode);
766  }
767  } else if (c->kwin_server_decoration_manager) {
768  data->kwin_server_decoration = org_kde_kwin_server_decoration_manager_create(c->kwin_server_decoration_manager, data->surface);
769  if (data->kwin_server_decoration) {
770  const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
772  org_kde_kwin_server_decoration_request_mode(data->kwin_server_decoration, mode);
773  }
774  }
775 
776  region = wl_compositor_create_region(c->compositor);
777  wl_region_add(region, 0, 0, window->w, window->h);
778  wl_surface_set_opaque_region(data->surface, region);
779  wl_region_destroy(region);
780 
781  if (c->relative_mouse_mode) {
783  }
784 
785  wl_surface_commit(data->surface);
786  WAYLAND_wl_display_flush(c->display);
787 
788  /* we have to wait until the surface gets a "configure" event, or
789  use of this surface will fail. This is a new rule for xdg_shell. */
790  if (c->shell.xdg) {
791  if (data->shell_surface.xdg.surface) {
792  while (!data->shell_surface.xdg.initial_configure_seen) {
793  WAYLAND_wl_display_flush(c->display);
794  WAYLAND_wl_display_dispatch(c->display);
795  }
796  }
797  } else if (c->shell.zxdg) {
798  if (data->shell_surface.zxdg.surface) {
799  while (!data->shell_surface.zxdg.initial_configure_seen) {
800  WAYLAND_wl_display_flush(c->display);
801  WAYLAND_wl_display_dispatch(c->display);
802  }
803  }
804  }
805 
806  return 0;
807 }
808 
809 
810 void
812 {
813  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
814 
815  if (data->resize.pending) {
816  struct wl_region *region;
817  if (data->scale_factor != data->resize.scale_factor) {
818  window->w = 0;
819  window->h = 0;
820  }
821  SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, data->resize.width, data->resize.height);
822  window->w = data->resize.width;
823  window->h = data->resize.height;
824  data->scale_factor = data->resize.scale_factor;
825  wl_surface_set_buffer_scale(data->surface, data->scale_factor);
826  if (data->egl_window) {
827  WAYLAND_wl_egl_window_resize(data->egl_window, window->w * data->scale_factor, window->h * data->scale_factor, 0, 0);
828  }
829 
830  if (data->resize.configure) {
831  if (data->waylandData->shell.xdg) {
832  xdg_surface_ack_configure(data->shell_surface.xdg.surface, data->resize.serial);
833  } else if (data->waylandData->shell.zxdg) {
834  zxdg_surface_v6_ack_configure(data->shell_surface.zxdg.surface, data->resize.serial);
835  }
836  data->resize.configure = SDL_FALSE;
837  }
838 
839  region = wl_compositor_create_region(data->waylandData->compositor);
840  wl_region_add(region, 0, 0, window->w, window->h);
841  wl_surface_set_opaque_region(data->surface, region);
842  wl_region_destroy(region);
843 
844  data->resize.pending = SDL_FALSE;
845  }
846 }
847 
849 {
851  SDL_WindowData *wind = window->driverdata;
852  struct wl_region *region;
853 
854  wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
855 
856  if (wind->egl_window) {
857  WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
858  }
859 
860  region = wl_compositor_create_region(data->compositor);
861  wl_region_add(region, 0, 0, window->w, window->h);
862  wl_surface_set_opaque_region(wind->surface, region);
863  wl_region_destroy(region);
864 }
865 
867 {
868  SDL_WindowData *wind = window->driverdata;
870 
871  if (window->title != NULL) {
872  if (viddata->shell.xdg) {
874  } else if (viddata->shell.zxdg) {
876  } else {
878  }
879  }
880 
881  WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
882 }
883 
885 {
887  SDL_WindowData *wind = window->driverdata;
888 
889  if (data) {
890  if (wind->egl_surface) {
891  SDL_EGL_DestroySurface(_this, wind->egl_surface);
892  }
893  if (wind->egl_window) {
894  WAYLAND_wl_egl_window_destroy(wind->egl_window);
895  }
896 
897  if (wind->server_decoration) {
899  }
900 
901  if (wind->kwin_server_decoration) {
903  }
904 
905  if (data->shell.xdg) {
906  if (wind->shell_surface.xdg.roleobj.toplevel) {
908  }
909  if (wind->shell_surface.zxdg.surface) {
911  }
912  } else if (data->shell.zxdg) {
913  if (wind->shell_surface.zxdg.roleobj.toplevel) {
915  }
916  if (wind->shell_surface.zxdg.surface) {
918  }
919  } else {
920  if (wind->shell_surface.wl) {
922  }
923  }
924 
925 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
926  if (wind->extended_surface) {
927  QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
928  QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
929  qt_extended_surface_destroy(wind->extended_surface);
930  }
931 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
933 
934  SDL_free(wind);
935  WAYLAND_wl_display_flush(data->display);
936  }
937  window->driverdata = NULL;
938 }
939 
940 #endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
941 
942 /* vi: set ts=4 sw=4 expandtab: */
#define _THIS
unsigned int uint32_t
signed int int32_t
#define SDL_SetError
#define SDL_DelHintCallback
#define SDL_GL_LoadLibrary
#define SDL_realloc
#define SDL_free
#define SDL_AddHintCallback
#define SDL_memmove
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
SDL_EventEntry * free
Definition: SDL_events.c:89
#define SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION
A variable describing the content orientation on QtWayland-based platforms.
Definition: SDL_hints.h:773
#define SDL_HINT_QTWAYLAND_WINDOW_FLAGS
Flags to set on QtWayland windows to integrate with the native window manager.
Definition: SDL_hints.h:784
#define SDLCALL
Definition: SDL_internal.h:49
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLenum mode
GLenum GLenum GLenum GLenum GLenum scale
const GLubyte * c
GLuint const GLchar * name
GLbitfield flags
GLsizei const GLfloat * value
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_min(x, y)
Definition: SDL_stdinc.h:412
uint32_t Uint32
Definition: SDL_stdinc.h:209
#define SDL_max(x, y)
Definition: SDL_stdinc.h:413
#define FULLSCREEN_VISIBLE(W)
Definition: SDL_sysvideo.h:117
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:587
@ SDL_SYSWM_UNKNOWN
Definition: SDL_syswm.h:129
@ SDL_SYSWM_WAYLAND
Definition: SDL_syswm.h:135
static SDL_VideoDevice * _this
Definition: SDL_video.c:126
#define SDL_WINDOWPOS_UNDEFINED
Definition: SDL_video.h:130
@ SDL_WINDOW_ALLOW_HIGHDPI
Definition: SDL_video.h:112
@ SDL_WINDOW_VULKAN
Definition: SDL_video.h:121
@ SDL_WINDOW_OPENGL
Definition: SDL_video.h:100
@ SDL_WINDOW_RESIZABLE
Definition: SDL_video.h:104
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:99
@ SDL_WINDOW_BORDERLESS
Definition: SDL_video.h:103
@ SDL_WINDOWEVENT_CLOSE
Definition: SDL_video.h:167
@ SDL_WINDOWEVENT_RESIZED
Definition: SDL_video.h:155
int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
int Wayland_input_confine_pointer(SDL_Window *window, struct SDL_WaylandInput *input)
int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input)
struct xkb_state * state
void Wayland_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *_display, SDL_bool fullscreen)
SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *info)
void Wayland_RestoreWindow(_THIS, SDL_Window *window)
void Wayland_HandlePendingResize(SDL_Window *window)
void Wayland_SetWindowTitle(_THIS, SDL_Window *window)
int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
void Wayland_ShowWindow(_THIS, SDL_Window *window)
int Wayland_CreateWindow(_THIS, SDL_Window *window)
void Wayland_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
void Wayland_SetWindowSize(_THIS, SDL_Window *window)
void Wayland_DestroyWindow(_THIS, SDL_Window *window)
void Wayland_MaximizeWindow(_THIS, SDL_Window *window)
void Wayland_SetWindowBordered(_THIS, SDL_Window *window, SDL_bool bordered)
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
#define EGL_NO_SURFACE
Definition: egl.h:100
EGLSurface surface
Definition: eglext.h:248
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
EGLNativeWindowType NativeWindowType
Definition: eglplatform.h:112
static struct org_kde_kwin_server_decoration * org_kde_kwin_server_decoration_manager_create(struct org_kde_kwin_server_decoration_manager *org_kde_kwin_server_decoration_manager, struct wl_surface *surface)
static void org_kde_kwin_server_decoration_request_mode(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration, uint32_t mode)
static void org_kde_kwin_server_decoration_release(struct org_kde_kwin_server_decoration *org_kde_kwin_server_decoration)
static struct wl_surface * wl_compositor_create_surface(struct wl_compositor *wl_compositor)
static struct wl_region * wl_compositor_create_region(struct wl_compositor *wl_compositor)
static void * wl_output_get_user_data(struct wl_output *wl_output)
static void wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
static void wl_region_destroy(struct wl_region *wl_region)
static void wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
static void wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
static void wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data)
static void wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
static void wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
static int wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface, const struct wl_shell_surface_listener *listener, void *data)
static void wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
static void wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
static void wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
@ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT
static struct wl_shell_surface * wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface)
static void wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
static void wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
static void wl_surface_destroy(struct wl_surface *wl_surface)
static int wl_surface_add_listener(struct wl_surface *wl_surface, const struct wl_surface_listener *listener, void *data)
static void wl_surface_commit(struct wl_surface *wl_surface)
static int xdg_surface_add_listener(struct xdg_surface *xdg_surface, const struct xdg_surface_listener *listener, void *data)
static void xdg_surface_destroy(struct xdg_surface *xdg_surface)
static struct xdg_toplevel * xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
static void xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
static void xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
static void xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
static void xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
static void xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
static void xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
static int xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, const struct xdg_toplevel_listener *listener, void *data)
static void xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
static void xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
@ XDG_TOPLEVEL_STATE_FULLSCREEN
static struct xdg_surface * xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
static struct zxdg_toplevel_decoration_v1 * zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
static struct zxdg_surface_v6 * zxdg_shell_v6_get_xdg_surface(struct zxdg_shell_v6 *zxdg_shell_v6, struct wl_surface *surface)
static int zxdg_surface_v6_add_listener(struct zxdg_surface_v6 *zxdg_surface_v6, const struct zxdg_surface_v6_listener *listener, void *data)
static void zxdg_surface_v6_set_user_data(struct zxdg_surface_v6 *zxdg_surface_v6, void *user_data)
static void zxdg_surface_v6_destroy(struct zxdg_surface_v6 *zxdg_surface_v6)
static void zxdg_surface_v6_ack_configure(struct zxdg_surface_v6 *zxdg_surface_v6, uint32_t serial)
static struct zxdg_toplevel_v6 * zxdg_surface_v6_get_toplevel(struct zxdg_surface_v6 *zxdg_surface_v6)
static void zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
static void zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
static void zxdg_toplevel_v6_set_title(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const char *title)
static void zxdg_toplevel_v6_set_fullscreen(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_output *output)
static void zxdg_toplevel_v6_unset_fullscreen(struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
static void zxdg_toplevel_v6_set_maximized(struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
static void zxdg_toplevel_v6_set_app_id(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const char *app_id)
static void zxdg_toplevel_v6_destroy(struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
static int zxdg_toplevel_v6_add_listener(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, const struct zxdg_toplevel_v6_listener *listener, void *data)
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
union SDL_SysWMinfo::@10 info
struct SDL_SysWMinfo::@10::@12 wl
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:219
SDL_version version
Definition: SDL_syswm.h:218
struct zxdg_shell_v6 * zxdg
struct xdg_wm_base * xdg
struct SDL_VideoData::@442 shell
struct wl_compositor * compositor
struct zxdg_decoration_manager_v1 * decoration_manager
struct org_kde_kwin_server_decoration_manager * kwin_server_decoration_manager
struct wl_display * display
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:326
struct wl_egl_window * egl_window
SDL_Surface * surface
struct zxdg_toplevel_decoration_v1 * server_decoration
struct qt_extended_surface * extended_surface
SDL_VideoData * waylandData
SDL_Window * sdlwindow
EGLSurface egl_surface
SDL_xdg_shell_surface xdg
struct wl_shell_surface * wl
struct org_kde_kwin_server_decoration * kwin_server_decoration
struct SDL_WindowData::@446 resize
union SDL_WindowData::@445 shell_surface
SDL_zxdg_shell_surface zxdg
The type used to identify a window.
Definition: SDL_sysvideo.h:75
Uint8 minor
Definition: SDL_version.h:54
Uint8 patch
Definition: SDL_version.h:55
Uint8 major
Definition: SDL_version.h:53
struct xdg_surface * surface
struct xdg_toplevel * toplevel
union SDL_xdg_shell_surface::@444 roleobj
struct zxdg_toplevel_v6 * toplevel
union SDL_zxdg_shell_surface::@443 roleobj
struct zxdg_surface_v6 * surface
#define strdup