wayland: client-side decoration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 665bca6..6df2656 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -388,6 +388,7 @@ set_option(CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" O
set_option(VIDEO_X11 "Use X11 video driver" ${UNIX_SYS})
set_option(VIDEO_WAYLAND "Use Wayland video driver" ${UNIX_SYS})
dep_option(WAYLAND_SHARED "Dynamically load Wayland support" ON "VIDEO_WAYLAND" OFF)
+dep_option(WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "VIDEO_WAYLAND" ON)
dep_option(VIDEO_WAYLAND_QT_TOUCH "QtWayland server support for Wayland video driver" ON "VIDEO_WAYLAND" OFF)
set_option(VIDEO_RPI "Use Raspberry Pi video driver" ${UNIX_SYS})
dep_option(X11_SHARED "Dynamically load X11 support" ON "VIDEO_X11" OFF)
@@ -2593,6 +2594,9 @@ if(SDL_SHARED)
set_property(TARGET SDL2 APPEND_STRING PROPERTY COMPILE_FLAGS "-fobjc-arc")
target_compile_definitions(SDL2 PRIVATE IOS_DYLIB=1)
endif()
+ if(WAYLAND_LIBDECOR)
+ target_include_directories(SDL2 PRIVATE "${libdecor_INCLUDE_DIRS}")
+ endif()
endif()
if(ANDROID)
@@ -2644,6 +2648,10 @@ if(SDL_STATIC)
if(IOS OR TVOS)
set_property(TARGET SDL2-static APPEND_STRING PROPERTY COMPILE_FLAGS "-fobjc-arc")
endif()
+ if(WAYLAND_LIBDECOR)
+ target_include_directories(SDL2-static PRIVATE "${libdecor_INCLUDE_DIRS}")
+ target_link_libraries(SDL2-static "${libdecor_LIBRARIES}")
+ endif()
endif()
##### Tests #####
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index d3f6cec..8df5925 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -697,6 +697,15 @@ macro(CheckWayland)
set(EXTRA_LIBS ${WAYLAND_LIBRARIES} ${EXTRA_LIBS})
endif()
+ if(WAYLAND_LIBDECOR)
+ pkg_check_modules(libdecor REQUIRED libdecor-0)
+
+ FindLibraryAndSONAME(decor-0)
+ set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR "\"${DECOR_0_LIB_SONAME}\"")
+
+ add_definitions(-DHAVE_LIBDECOR_H)
+ endif()
+
set(SDL_VIDEO_DRIVER_WAYLAND 1)
endif()
endif()
diff --git a/configure.ac b/configure.ac
index 10879ee..615048e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2777,6 +2777,43 @@ CheckFcitx()
fi
}
+dnl See if libdecor is available
+CheckLibDecor()
+{
+ AC_ARG_ENABLE(libdecor,
+[AS_HELP_STRING([--enable-libdecor], [use libdecor for Wayland client-side decorations [default=yes]])],
+ , enable_libdecor=yes)
+ if test x$enable_libdecor = xyes; then
+ AC_MSG_CHECKING(for libdecor support)
+ AS_IF([$PKG_CONFIG --exists libdecor-0],
+ [video_libdecor=yes],
+ [video_libdecor=no])
+ AC_MSG_RESULT($video_libdecor)
+ if test x$video_libdecor = xyes; then
+ EXTRA_CFLAGS="$EXTRA_CFLAGS `$PKG_CONFIG --cflags libdecor-0`"
+ AC_DEFINE(HAVE_LIBDECOR_H, 1, [ ])
+
+ AC_ARG_ENABLE(libdecor-shared,
+[AS_HELP_STRING([--enable-libdecor-shared], [dynamically load libdecor [default=yes]])],
+ , enable_libdecor_shared=yes)
+
+ decor_lib=[`find_lib "libdecor-0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'`]
+
+ if test x$have_loadso != xyes && \
+ test x$enable_libdecor_shared = xyes; then
+ AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic libdecor loading])
+ fi
+ if test x$have_loadso = xyes && \
+ test x$enable_libdecor_shared = xyes && test x$decor_lib != x; then
+ echo "-- dynamic libdecor -> $decor_lib"
+ AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR, "$decor_lib", [ ])
+ else
+ EXTRA_LDFLAGS="$EXTRA_LDFLAGS `$PKG_CONFIG --libs libdecor-0`"
+ fi
+ fi
+ fi
+}
+
dnl Check to see if GameController framework support is desired
CheckJoystickMFI()
{
@@ -3572,6 +3609,7 @@ case "$host" in
CheckInotify
CheckIBus
CheckFcitx
+ CheckLibDecor
case $ARCH in
linux)
CheckInputKD
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 40c5a7e..897d06a 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -387,6 +387,7 @@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR@
#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR@
#cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@
#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index 9ddd932..ea87723 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -225,6 +225,7 @@
#undef HAVE_IMMINTRIN_H
#undef HAVE_LIBUDEV_H
#undef HAVE_LIBSAMPLERATE_H
+#undef HAVE_LIBDECOR_H
#undef HAVE_DDRAW_H
#undef HAVE_DINPUT_H
@@ -365,6 +366,7 @@
#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
+#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
#undef SDL_VIDEO_DRIVER_X11
#undef SDL_VIDEO_DRIVER_RPI
#undef SDL_VIDEO_DRIVER_KMSDRM
diff --git a/src/video/wayland/SDL_waylanddyn.c b/src/video/wayland/SDL_waylanddyn.c
index e729861..2bbc49e 100644
--- a/src/video/wayland/SDL_waylanddyn.c
+++ b/src/video/wayland/SDL_waylanddyn.c
@@ -47,12 +47,16 @@ typedef struct
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON NULL
#endif
+#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
+#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR NULL
+#endif
static waylanddynlib waylandlibs[] = {
{NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC},
{NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL},
{NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR},
- {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON}
+ {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON},
+ {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR}
};
static void *
diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h
index 55ac1eb..eef24a6 100644
--- a/src/video/wayland/SDL_waylanddyn.h
+++ b/src/video/wayland/SDL_waylanddyn.h
@@ -34,6 +34,19 @@ struct wl_display;
struct wl_surface;
struct wl_shm;
+/* We also need some for libdecor */
+struct wl_seat;
+struct wl_output;
+struct libdecor;
+struct libdecor_frame;
+struct libdecor_state;
+struct libdecor_configuration;
+struct libdecor_interface;
+struct libdecor_frame_interface;
+enum libdecor_resize_edge;
+enum libdecor_capabilities;
+enum libdecor_window_state;
+
#include <stdint.h>
#include "wayland-cursor.h"
#include "wayland-util.h"
@@ -82,6 +95,8 @@ void SDL_WAYLAND_UnloadSymbols(void);
#define wl_proxy_add_listener (*WAYLAND_wl_proxy_add_listener)
#define wl_proxy_marshal_constructor (*WAYLAND_wl_proxy_marshal_constructor)
#define wl_proxy_marshal_constructor_versioned (*WAYLAND_wl_proxy_marshal_constructor_versioned)
+#define wl_proxy_set_tag (*WAYLAND_wl_proxy_set_tag)
+#define wl_proxy_get_tag (*WAYLAND_wl_proxy_get_tag)
#define wl_seat_interface (*WAYLAND_wl_seat_interface)
#define wl_surface_interface (*WAYLAND_wl_surface_interface)
@@ -101,6 +116,35 @@ void SDL_WAYLAND_UnloadSymbols(void);
#define wl_data_source_interface (*WAYLAND_wl_data_source_interface)
#define wl_data_device_manager_interface (*WAYLAND_wl_data_device_manager_interface)
+#ifdef HAVE_LIBDECOR_H
+/* Must be included before our defines */
+#include <libdecor.h>
+
+#define libdecor_unref (*WAYLAND_libdecor_unref)
+#define libdecor_new (*WAYLAND_libdecor_new)
+#define libdecor_decorate (*WAYLAND_libdecor_decorate)
+#define libdecor_frame_unref (*WAYLAND_libdecor_frame_unref)
+#define libdecor_frame_set_title (*WAYLAND_libdecor_frame_set_title)
+#define libdecor_frame_set_app_id (*WAYLAND_libdecor_frame_set_app_id)
+#define libdecor_frame_set_max_content_size (*WAYLAND_libdecor_frame_set_max_content_size)
+#define libdecor_frame_set_min_content_size (*WAYLAND_libdecor_frame_set_min_content_size)
+#define libdecor_frame_resize (*WAYLAND_libdecor_frame_resize)
+#define libdecor_frame_move (*WAYLAND_libdecor_frame_move)
+#define libdecor_frame_commit (*WAYLAND_libdecor_frame_commit)
+#define libdecor_frame_set_minimized (*WAYLAND_libdecor_frame_set_minimized)
+#define libdecor_frame_set_maximized (*WAYLAND_libdecor_frame_set_maximized)
+#define libdecor_frame_unset_maximized (*WAYLAND_libdecor_frame_unset_maximized)
+#define libdecor_frame_set_fullscreen (*WAYLAND_libdecor_frame_set_fullscreen)
+#define libdecor_frame_unset_fullscreen (*WAYLAND_libdecor_frame_unset_fullscreen)
+#define libdecor_frame_set_capabilities (*WAYLAND_libdecor_frame_set_capabilities)
+#define libdecor_frame_unset_capabilities (*WAYLAND_libdecor_frame_unset_capabilities)
+#define libdecor_frame_map (*WAYLAND_libdecor_frame_map)
+#define libdecor_state_new (*WAYLAND_libdecor_state_new)
+#define libdecor_state_free (*WAYLAND_libdecor_state_free)
+#define libdecor_configuration_get_content_size (*WAYLAND_libdecor_configuration_get_content_size)
+#define libdecor_configuration_get_window_state (*WAYLAND_libdecor_configuration_get_window_state)
+#endif
+
#endif /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */
#include "wayland-client-protocol.h"
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index b69171a..d0c6811 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -43,6 +43,10 @@
#include "xdg-shell-unstable-v6-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
+#ifdef HAVE_LIBDECOR_H
+#include <libdecor.h>
+#endif
+
#ifdef SDL_INPUT_LINUXEV
#include <linux/input.h>
#else
@@ -272,6 +276,11 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
return;
}
+ /* check that this surface belongs to one of the SDL windows */
+ if (!SDL_WAYLAND_own_surface(surface)) {
+ return;
+ }
+
/* This handler will be called twice in Wayland 1.4
* Once for the window surface which has valid user data
* and again for the mouse cursor surface which does not have valid user data
@@ -301,6 +310,10 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer,
{
struct SDL_WaylandInput *input = data;
+ if (!surface || !SDL_WAYLAND_own_surface(surface)) {
+ return;
+ }
+
if (input->pointer_focus) {
SDL_SetMouseFocus(NULL);
input->pointer_focus = NULL;
@@ -328,8 +341,20 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */
const uint32_t *directions_zxdg = directions_wl;
+#ifdef HAVE_LIBDECOR_H
+ /* ditto for libdecor. */
+ const uint32_t *directions_libdecor = directions_wl;
+#endif
+
switch (rc) {
case SDL_HITTEST_DRAGGABLE:
+#ifdef HAVE_LIBDECOR_H
+ if (input->display->shell.libdecor) {
+ if (window_data->shell_surface.libdecor.frame) {
+ libdecor_frame_move(window_data->shell_surface.libdecor.frame, input->seat, serial);
+ }
+ } else
+#endif
if (input->display->shell.xdg) {
if (window_data->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel,
@@ -357,6 +382,13 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
case SDL_HITTEST_RESIZE_BOTTOM:
case SDL_HITTEST_RESIZE_BOTTOMLEFT:
case SDL_HITTEST_RESIZE_LEFT:
+#ifdef HAVE_LIBDECOR_H
+ if (input->display->shell.libdecor) {
+ if (window_data->shell_surface.libdecor.frame) {
+ libdecor_frame_resize(window_data->shell_surface.libdecor.frame, input->seat, serial, directions_libdecor[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
+ }
+ } else
+#endif
if (input->display->shell.xdg) {
if (window_data->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel,
@@ -723,6 +755,10 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
return;
}
+ if (!SDL_WAYLAND_own_surface(surface)) {
+ return;
+ }
+
window = wl_surface_get_user_data(surface);
if (window) {
@@ -741,6 +777,10 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
{
struct SDL_WaylandInput *input = data;
+ if (!surface || !SDL_WAYLAND_own_surface(surface)) {
+ return;
+ }
+
/* Stop key repeat before clearing keyboard focus */
keyboard_repeat_clear(&input->keyboard_repeat);
diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h
index 278c4ff..76b9c27 100644
--- a/src/video/wayland/SDL_waylandsym.h
+++ b/src/video/wayland/SDL_waylandsym.h
@@ -33,6 +33,8 @@
#define SDL_WAYLAND_INTERFACE(iface)
#endif
+#include <stdbool.h>
+
SDL_WAYLAND_MODULE(WAYLAND_CLIENT)
SDL_WAYLAND_SYM(void, wl_proxy_marshal, (struct wl_proxy *, uint32_t, ...))
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_create, (struct wl_proxy *, const struct wl_interface *))
@@ -71,6 +73,10 @@ SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_prox
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_10)
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...))
+SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_18)
+SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *))
+SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *))
+
SDL_WAYLAND_INTERFACE(wl_seat_interface)
SDL_WAYLAND_INTERFACE(wl_surface_interface)
SDL_WAYLAND_INTERFACE(wl_shm_pool_interface)
@@ -134,6 +140,53 @@ SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *,
const xkb_keysym_t **) )
SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) )
+#ifdef HAVE_LIBDECOR_H
+SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR)
+SDL_WAYLAND_SYM(void, libdecor_unref, (struct libdecor *))
+SDL_WAYLAND_SYM(struct libdecor *, libdecor_new, (struct wl_display *, struct libdecor_interface *))
+SDL_WAYLAND_SYM(struct libdecor_frame *, libdecor_decorate, (struct libdecor *,\
+ struct wl_surface *,\
+ struct libdecor_frame_interface *,\
+ void *))
+SDL_WAYLAND_SYM(void, libdecor_frame_unref, (struct libdecor_frame *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_title, (struct libdecor_frame *, const char *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_app_id, (struct libdecor_frame *, const char *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_max_content_size, (struct libdecor_frame *frame,\
+ int content_width,\
+ int content_height))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_min_content_size, (struct libdecor_frame *frame,\
+ int content_width,\
+ int content_height))
+SDL_WAYLAND_SYM(void, libdecor_frame_resize, (struct libdecor_frame *,\
+ struct wl_seat *,\
+ uint32_t,\
+ enum libdecor_resize_edge))
+SDL_WAYLAND_SYM(void, libdecor_frame_move, (struct libdecor_frame *,\
+ struct wl_seat *,\
+ uint32_t))
+SDL_WAYLAND_SYM(void, libdecor_frame_commit, (struct libdecor_frame *,\
+ struct libdecor_state *,\
+ struct libdecor_configuration *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_minimized, (struct libdecor_frame *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_maximized, (struct libdecor_frame *))
+SDL_WAYLAND_SYM(void, libdecor_frame_unset_maximized, (struct libdecor_frame *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_fullscreen, (struct libdecor_frame *, struct wl_output *))
+SDL_WAYLAND_SYM(void, libdecor_frame_unset_fullscreen, (struct libdecor_frame *))
+SDL_WAYLAND_SYM(void, libdecor_frame_set_capabilities, (struct libdecor_frame *, \
+ enum libdecor_capabilities))
+SDL_WAYLAND_SYM(void, libdecor_frame_unset_capabilities, (struct libdecor_frame *, \
+ enum libdecor_capabilities))
+SDL_WAYLAND_SYM(void, libdecor_frame_map, (struct libdecor_frame *))
+SDL_WAYLAND_SYM(struct libdecor_state *, libdecor_state_new, (int, int))
+SDL_WAYLAND_SYM(void, libdecor_state_free, (struct libdecor_state *))
+SDL_WAYLAND_SYM(bool, libdecor_configuration_get_content_size, (struct libdecor_configuration *,\
+ struct libdecor_frame *,\
+ int *,\
+ int *))
+SDL_WAYLAND_SYM(bool, libdecor_configuration_get_window_state, (struct libdecor_configuration *,\
+ enum libdecor_window_state *))
+#endif
+
#undef SDL_WAYLAND_MODULE
#undef SDL_WAYLAND_SYM
#undef SDL_WAYLAND_INTERFACE
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 44b2163..ba5dc23 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -53,6 +53,10 @@
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
+#ifdef HAVE_LIBDECOR_H
+#include <libdecor.h>
+#endif
+
#define WAYLANDVID_DRIVER_NAME "wayland"
/* Initialization/Query functions */
@@ -433,6 +437,21 @@ static const struct xdg_wm_base_listener shell_listener_xdg = {
};
+#ifdef HAVE_LIBDECOR_H
+static void
+libdecor_error(struct libdecor *context,
+ enum libdecor_error error,
+ const char *message)
+{
+ SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "libdecor error (%d): %s\n", error, message);
+}
+
+static struct libdecor_interface libdecor_interface = {
+ libdecor_error,
+};
+#endif
+
+
static void
display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
@@ -447,13 +466,25 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
Wayland_add_display(d, id);
} else if (SDL_strcmp(interface, "wl_seat") == 0) {
Wayland_display_add_input(d, id, version);
- } else if (SDL_strcmp(interface, "xdg_wm_base") == 0) {
+ } else if (
+#ifdef HAVE_LIBDECOR_H
+ !d->shell.libdecor &&
+#endif
+ SDL_strcmp(interface, "xdg_wm_base") == 0) {
d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL);
- } else if (SDL_strcmp(interface, "zxdg_shell_v6") == 0) {
+ } else if (
+#ifdef HAVE_LIBDECOR_H
+ !d->shell.libdecor &&
+#endif
+ SDL_strcmp(interface, "zxdg_shell_v6") == 0) {
d->shell.zxdg = wl_registry_bind(d->registry, id, &zxdg_shell_v6_interface, 1);
zxdg_shell_v6_add_listener(d->shell.zxdg, &shell_listener_zxdg, NULL);
- } else if (SDL_strcmp(interface, "wl_shell") == 0) {
+ } else if (
+#ifdef HAVE_LIBDECOR_H
+ !d->shell.libdecor &&
+#endif
+ SDL_strcmp(interface, "wl_shell") == 0) {
d->shell.wl = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
} else if (SDL_strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
@@ -510,6 +541,12 @@ Wayland_VideoInit(_THIS)
return SDL_SetError("Failed to get the Wayland registry");
}
+#ifdef HAVE_LIBDECOR_H
+ if (SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR) {
+ data->shell.libdecor = libdecor_new(data->display, &libdecor_interface);
+ }
+#endif
+
wl_registry_add_listener(data->registry, ®istry_listener, data);
// First roundtrip to receive all registry objects.
@@ -632,6 +669,13 @@ Wayland_VideoQuit(_THIS)
if (data->decoration_manager)
zxdg_decoration_manager_v1_destroy(data->decoration_manager);
+#ifdef HAVE_LIBDECOR_H
+ if (data->shell.libdecor) {
+ libdecor_unref(data->shell.libdecor);
+ data->shell.libdecor = NULL;
+ }
+#endif
+
if (data->compositor)
wl_compositor_destroy(data->compositor);
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 0c6957f..54201e2 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -62,6 +62,9 @@ typedef struct {
struct xdg_wm_base *xdg;
struct zxdg_shell_v6 *zxdg;
struct wl_shell *wl;
+#ifdef HAVE_LIBDECOR_H
+ struct libdecor *libdecor;
+#endif
} shell;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index c18e159..cc843c7 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -39,6 +39,20 @@
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
+#ifdef HAVE_LIBDECOR_H
+#include <libdecor.h>
+#endif
+
+static const char *SDL_WAYLAND_surface_tag = "sdl-window";
+
+SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface)
+{
+ if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
+ return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
+ }
+ return SDL_TRUE; /* For older clients we have to assume this is us... */
+}
+
static float get_window_scale_factor(SDL_Window *window) {
return ((SDL_WindowData*)window->driverdata)->scale_factor;
}
@@ -67,6 +81,19 @@ CommitMinMaxDimensions(SDL_Window *window)
max_height = window->windowed.h;
}
+#ifdef HAVE_LIBDECOR_H
+ if (data->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ libdecor_frame_set_min_content_size(wind->shell_surface.libdecor.frame,
+ min_width,
+ min_height);
+ libdecor_frame_set_max_content_size(wind->shell_surface.libdecor.frame,
+ max_width,
+ max_height);
+ } else
+#endif
if (data->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
@@ -77,6 +104,7 @@ CommitMinMaxDimensions(SDL_Window *window)
xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel,
max_width,
max_height);
+ wl_surface_commit(wind->surface);
} else if (data->shell.zxdg) {
if (wind->shell_surface.zxdg.roleobj.toplevel == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
@@ -87,9 +115,8 @@ CommitMinMaxDimensions(SDL_Window *window)
zxdg_toplevel_v6_set_max_size(wind->shell_surface.zxdg.roleobj.toplevel,
max_width,
max_height);
+ wl_surface_commit(wind->surface);
}
-
- wl_surface_commit(wind->surface);
}
static void
@@ -103,6 +130,18 @@ SetFullscreen(SDL_Window *window, struct wl_output *output)
*/
CommitMinMaxDimensions(window);
+#ifdef HAVE_LIBDECOR_H
+ if (viddata->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ if (output) {
+ libdecor_frame_set_fullscreen(wind->shell_surface.libdecor.frame, output);
+ } else {
+ libdecor_frame_unset_fullscreen(wind->shell_surface.libdecor.frame);
+ }
+ } else
+#endif
if (viddata->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
@@ -481,8 +520,97 @@ static const struct xdg_toplevel_listener toplevel_listener_xdg = {
handle_close_xdg_toplevel
};
+#ifdef HAVE_LIBDECOR_H
+static void
+decoration_frame_configure(struct libdecor_frame *frame,
+ struct libdecor_configuration *configuration,
+ void *user_data)
+{
+ SDL_WindowData *wind = user_data;
+ SDL_Window *window = wind->sdlwindow;
+ int width, height;
+ enum libdecor_window_state window_state;
+ struct libdecor_state *state;
+
+ /* window size */
+ if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
+ width = window->w;
+ height = window->h;
+ }
+
+ wind->resize.width = width;
+ wind->resize.height = height;
+
+ wind->resize.pending = SDL_TRUE;
+ wind->resize.configure = SDL_TRUE;
+ Wayland_HandlePendingResize(window);
+ wind->shell_surface.libdecor.initial_configure_seen = SDL_TRUE;
+
+ window->w = wind->resize.width;
+ window->h = wind->resize.height;
+
+ /* window state */
+ if (!libdecor_configuration_get_window_state(configuration, &window_state)) {
+ window_state = LIBDECOR_WINDOW_STATE_NONE;
+ }
+
+ if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) {
+ window->flags |= SDL_WINDOW_MAXIMIZED;
+ }
+ else {
+ window->flags &= ~SDL_WINDOW_MAXIMIZED;
+ }
+
+ if (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) {
+ window->flags |= SDL_WINDOW_INPUT_FOCUS;
+ }
+ else {
+ window->flags &= ~SDL_WINDOW_INPUT_FOCUS;
+ }
+
+ /* The fullscreen flag is already set my some other entity when 'SDL_SetWindowFullscreen'
+ * is called, but we will set it here again in case the compositor requests fullscreen.
+ */
+ if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) {
+ window->flags |= SDL_WINDOW_FULLSCREEN;
+ }
+ else {
+ window->flags &= ~SDL_WINDOW_FULLSCREEN;
+ }
+
+ /* commit frame state */
+ state = libdecor_state_new(width, height);
+ libdecor_frame_commit(frame, state, configuration);
+ libdecor_state_free(state);
+
+ /* Update the resize capability. Since this will change the capabilities and
+ * commit a new frame state with the last known content dimension, this has
+ * to be called after the new state has been commited and the new content
+ * dimensions were updated. */
+ Wayland_SetWindowResizable(SDL_GetVideoDevice(), window,
+ window->flags & SDL_WINDOW_RESIZABLE);
+}
+
+static void
+decoration_frame_close(struct libdecor_frame *frame, void *user_data)
+{
+ SDL_SendWindowEvent(((SDL_WindowData *)user_data)->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
+}
+
+static void
+decoration_frame_commit(struct libdecor_frame *frame, void *user_data)
+{
+ SDL_WindowData *wind = user_data;
+ SDL_SendWindowEvent(wind->sdlwindow, SDL_WINDOWEVENT_EXPOSED, 0, 0);
+}
+static struct libdecor_frame_interface libdecor_frame_interface = {
+ decoration_frame_configure,
+ decoration_frame_close,
+ decoration_frame_commit,
+};
+#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
static void
@@ -706,6 +834,20 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
wl_surface_commit(data->surface);
/* Create the shell surface and map the toplevel */
+#ifdef HAVE_LIBDECOR_H
+ if (c->shell.libdecor) {
+ data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor,
+ data->surface,
+ &libdecor_frame_interface,
+ data);
+ if (data->shell_surface.libdecor.frame == NULL) {
+ SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create libdecor frame!");
+ } else {
+ libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, c->classname);
+ libdecor_frame_map(data->shell_surface.libdecor.frame);
+ }
+ } else
+#endif
if (c->shell.xdg) {
data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface);
xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
@@ -744,6 +886,16 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
/* We have to wait until the surface gets a "configure" event, or use of
* this surface will fail. This is a new rule for xdg_shell.
*/
+#ifdef HAVE_LIBDECOR_H
+ if (c->shell.libdecor) {
+ if (data->shell_surface.libdecor.frame) {
+ while (!data->shell_surface.libdecor.initial_configure_seen) {
+ WAYLAND_wl_display_flush(c->display);
+ WAYLAND_wl_display_dispatch(c->display);
+ }
+ }
+ } else
+#endif
if (c->shell.xdg) {
if (data->shell_surface.xdg.surface) {
while (!data->shell_surface.xdg.initial_configure_seen) {
@@ -801,6 +953,14 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
wind->server_decoration = NULL;
}
+#ifdef HAVE_LIBDECOR_H
+ if (data->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame) {
+ libdecor_frame_unref(wind->shell_surface.libdecor.frame);
+ wind->shell_surface.libdecor.frame = NULL;
+ }
+ } else
+#endif
if (data->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
@@ -1027,6 +1187,14 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window)
*/
window->flags &= ~SDL_WINDOW_MAXIMIZED;
+#ifdef HAVE_LIBDECOR_H
+ if (viddata->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ libdecor_frame_unset_maximized(wind->shell_surface.libdecor.frame);
+ } else
+#endif
/* Note that xdg-shell does NOT provide a way to unset minimize! */
if (viddata->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel == NULL) {
@@ -1053,6 +1221,11 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
{
SDL_WindowData *wind = window->driverdata;
const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
+#ifdef HAVE_LIBDECOR_H
+ if (viddata->shell.libdecor) {
+ SDL_SetError("FIXME libdecor: Implement toggling decorations");
+ } else
+#endif
if ((viddata->decoration_manager) && (wind->server_decoration)) {
const enum zxdg_toplevel_decoration_v1_mode mode = bordered ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
zxdg_toplevel_decoration_v1_set_mode(wind->server_decoration, mode);
@@ -1062,7 +1235,24 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
void
Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
{
- CommitMinMaxDimensions(window);
+#ifdef HAVE_LIBDECOR_H
+ SDL_VideoData *data = _this->driverdata;
+ const SDL_WindowData *wind = window->driverdata;
+
+ if (data->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ if (resizable) {
+ libdecor_frame_set_capabilities(wind->shell_surface.libdecor.frame, LIBDECOR_ACTION_RESIZE);
+ } else {
+ libdecor_frame_unset_capabilities(wind->shell_surface.libdecor.frame, LIBDECOR_ACTION_RESIZE);
+ }
+ } else
+#endif
+ {
+ CommitMinMaxDimensions(window);
+ }
}
void
@@ -1080,6 +1270,14 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window)
*/
window->flags |= SDL_WINDOW_MAXIMIZED;
+#ifdef HAVE_LIBDECOR_H
+ if (viddata->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ libdecor_frame_set_maximized(wind->shell_surface.libdecor.frame);
+ } else
+#endif
if (viddata->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
@@ -1106,6 +1304,14 @@ Wayland_MinimizeWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
+#ifdef HAVE_LIBDECOR_H
+ if (viddata->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ libdecor_frame_set_minimized(wind->shell_surface.libdecor.frame);
+ } else
+#endif
if (viddata->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
@@ -1199,6 +1405,10 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
wl_compositor_create_surface(c->compositor);
wl_surface_add_listener(data->surface, &surface_listener, data);
+ if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
+ wl_proxy_set_tag((struct wl_proxy *)data->surface, &SDL_WAYLAND_surface_tag);
+ }
+
/* Fire a callback when the compositor wants a new frame rendered.
* Right now this only matters for OpenGL; we use this callback to add a
* wait timeout that avoids getting deadlocked by the compositor when the
@@ -1278,6 +1488,11 @@ Wayland_HandlePendingResize(SDL_Window *window)
}
if (data->resize.configure) {
+#ifdef HAVE_LIBDECOR_H
+ if (data->waylandData->shell.libdecor) {
+ /* this has already been acknowledged in the the frames's 'configure' callback */
+ } else
+#endif
if (data->waylandData->shell.xdg) {
xdg_surface_ack_configure(data->shell_surface.xdg.surface, data->resize.serial);
} else if (data->waylandData->shell.zxdg) {
@@ -1312,6 +1527,9 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
SDL_VideoData *data = _this->driverdata;
SDL_WindowData *wind = window->driverdata;
struct wl_region *region;
+#ifdef HAVE_LIBDECOR_H
+ struct libdecor_state *state;
+#endif
wl_surface_set_buffer_scale(wind->surface, get_window_scale_factor(window));
@@ -1319,6 +1537,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
WAYLAND_wl_egl_window_resize(wind->egl_window, window->w * get_window_scale_factor(window), window->h * get_window_scale_factor(window), 0, 0);
}
+#ifdef HAVE_LIBDECOR_H
+ if (data->shell.libdecor && wind->shell_surface.libdecor.frame) {
+ state = libdecor_state_new(window->w, window->h);
+ libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL);
+ libdecor_state_free(state);
+ }
+#endif
+
region = wl_compositor_create_region(data->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(wind->surface, region);
@@ -1331,6 +1557,14 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (window->title != NULL) {
+#ifdef HAVE_LIBDECOR_H
+ if (viddata->shell.libdecor) {
+ if (wind->shell_surface.libdecor.frame == NULL) {
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ libdecor_frame_set_title(wind->shell_surface.libdecor.frame, window->title);
+ } else
+#endif
if (viddata->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 5956cf3..493b50f 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -50,6 +50,13 @@ typedef struct {
SDL_bool initial_configure_seen;
} SDL_xdg_shell_surface;
+#ifdef HAVE_LIBDECOR_H
+typedef struct {
+ struct libdecor_frame *frame;
+ SDL_bool initial_configure_seen;
+} SDL_libdecor_surface;
+#endif
+
typedef struct {
SDL_Window *sdlwindow;
SDL_VideoData *waylandData;
@@ -58,6 +65,9 @@ typedef struct {
union {
SDL_xdg_shell_surface xdg;
SDL_zxdg_shell_surface zxdg;
+#ifdef HAVE_LIBDECOR_H
+ SDL_libdecor_surface libdecor;
+#endif
struct wl_shell_surface *wl;
} shell_surface;
struct wl_egl_window *egl_window;
@@ -117,6 +127,8 @@ extern int Wayland_FlashWindow(_THIS, SDL_Window * window, SDL_FlashOperation op
extern void Wayland_HandlePendingResize(SDL_Window *window);
+extern SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface);
+
#endif /* SDL_waylandwindow_h_ */
/* vi: set ts=4 sw=4 expandtab: */