Introduction ------------
This is the first of (many) parts in the upstreaming of the Wayland driver for Wine. Since the amount of code and commits is large, my approach is to upstream the driver in multiple parts in a serial fashion, with each part being a cohesive (to the degree possible) set of not too many commits. When each part is reviewed and merged, I will move on to proposing the next part. My main goal with this approach is to make reviewing easier and more focused. If you have other ideas about how to improve this process for the reviewers, please let me know.
A lot of pieces need to fall into place before the driver becomes even remotely functional, so, some MRs (especially the initial ones) will be a bit more preparatory in nature. To aid in the understanding of and justification for some of the code introduced in such MRs, all the remaining driver commits are always going to be available at https://gitlab.winehq.org/afrantzis/wine/-/tree/wayland.
Part 1 -------
~~This MR introduces the Wayland driver PE and unixlib components with some basic code, and prepares the makedep tool to be able to handle Wayland protocol files.~~ This MR introduces the Wayland driver PE and unixlib components with some basic code, and reports some basic monitor information to Wine.
Please see the individual commit message for more details.
Some questions I would appreciate some feedback on in the context of this MR:
1. Should the Wayland driver build be enabled by default at this point? (currently it's explicitly opt-in with --with-wayland) 2. How should the Wayland driver build be integrated with CI? (currently piggybacking on gitlab/build-linux by adding --with-wayland)
Note that building the Wayland driver should not affect running/testing on X11/Xwayland etc, since it's placed lower in the driver priority list.
~~Part 2 preview: We will handle basic Wayland wl_output (i.e., display) events and populate the Wine monitor information.~~ Part 2 preview: We will report more monitor information and implement GetCurrentDisplaySettings.
-- v7: winewayland.drv: Report all advertised monitor modes to Wine.
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Add the initial driver stub for the Wayland driver and build it by default.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- configure | 2 ++ configure.ac | 1 + dlls/winewayland.drv/Makefile.in | 6 +++++ dlls/winewayland.drv/dllmain.c | 30 +++++++++++++++++++++++ dlls/winewayland.drv/version.rc | 22 +++++++++++++++++ dlls/winewayland.drv/waylanddrv_dll.h | 28 +++++++++++++++++++++ dlls/winewayland.drv/winewayland.drv.spec | 0 7 files changed, 89 insertions(+) create mode 100644 dlls/winewayland.drv/Makefile.in create mode 100644 dlls/winewayland.drv/dllmain.c create mode 100644 dlls/winewayland.drv/version.rc create mode 100644 dlls/winewayland.drv/waylanddrv_dll.h create mode 100644 dlls/winewayland.drv/winewayland.drv.spec
diff --git a/configure b/configure index 7618e8b4b15..210409724f1 100755 --- a/configure +++ b/configure @@ -1473,6 +1473,7 @@ enable_wineps_drv enable_winepulse_drv enable_wineusb_sys enable_winevulkan +enable_winewayland_drv enable_winex11_drv enable_winexinput_sys enable_wing32 @@ -21733,6 +21734,7 @@ wine_fn_config_makefile dlls/wineps16.drv16 enable_win16 wine_fn_config_makefile dlls/winepulse.drv enable_winepulse_drv wine_fn_config_makefile dlls/wineusb.sys enable_wineusb_sys wine_fn_config_makefile dlls/winevulkan enable_winevulkan +wine_fn_config_makefile dlls/winewayland.drv enable_winewayland_drv wine_fn_config_makefile dlls/winex11.drv enable_winex11_drv wine_fn_config_makefile dlls/winexinput.sys enable_winexinput_sys wine_fn_config_makefile dlls/wing.dll16 enable_win16 diff --git a/configure.ac b/configure.ac index 35af177b013..da9e4c22891 100644 --- a/configure.ac +++ b/configure.ac @@ -3140,6 +3140,7 @@ WINE_CONFIG_MAKEFILE(dlls/wineps16.drv16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/winepulse.drv) WINE_CONFIG_MAKEFILE(dlls/wineusb.sys) WINE_CONFIG_MAKEFILE(dlls/winevulkan) +WINE_CONFIG_MAKEFILE(dlls/winewayland.drv) WINE_CONFIG_MAKEFILE(dlls/winex11.drv) WINE_CONFIG_MAKEFILE(dlls/winexinput.sys) WINE_CONFIG_MAKEFILE(dlls/wing.dll16,enable_win16) diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in new file mode 100644 index 00000000000..713b281b1bd --- /dev/null +++ b/dlls/winewayland.drv/Makefile.in @@ -0,0 +1,6 @@ +MODULE = winewayland.drv + +C_SRCS = \ + dllmain.c \ + +RC_SRCS = version.rc diff --git a/dlls/winewayland.drv/dllmain.c b/dlls/winewayland.drv/dllmain.c new file mode 100644 index 00000000000..7ab3341e61d --- /dev/null +++ b/dlls/winewayland.drv/dllmain.c @@ -0,0 +1,30 @@ +/* + * winewayland.drv entry points + * + * Copyright 2022 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "waylanddrv_dll.h" + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + if (reason != DLL_PROCESS_ATTACH) return TRUE; + + DisableThreadLibraryCalls(instance); + + return TRUE; +} diff --git a/dlls/winewayland.drv/version.rc b/dlls/winewayland.drv/version.rc new file mode 100644 index 00000000000..2d99c24f99c --- /dev/null +++ b/dlls/winewayland.drv/version.rc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINE_FILEDESCRIPTION_STR "Wine Wayland driver" +#define WINE_FILENAME_STR "winewayland.drv" + +#include "wine/wine_common_ver.rc" diff --git a/dlls/winewayland.drv/waylanddrv_dll.h b/dlls/winewayland.drv/waylanddrv_dll.h new file mode 100644 index 00000000000..556898d44b2 --- /dev/null +++ b/dlls/winewayland.drv/waylanddrv_dll.h @@ -0,0 +1,28 @@ +/* + * Wayland driver DLL definitions + * + * Copyright 2022 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WAYLANDDRV_DLL_H +#define __WINE_WAYLANDDRV_DLL_H + +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" + +#endif /* __WINE_WAYLANDDRV_DLL_H */ diff --git a/dlls/winewayland.drv/winewayland.drv.spec b/dlls/winewayland.drv/winewayland.drv.spec new file mode 100644 index 00000000000..e69de29bb2d
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/Makefile.in | 2 + dlls/winewayland.drv/dllmain.c | 4 ++ dlls/winewayland.drv/unixlib.h | 32 ++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 30 +++++++++++++++ dlls/winewayland.drv/waylanddrv_dll.h | 4 ++ dlls/winewayland.drv/waylanddrv_main.c | 53 ++++++++++++++++++++++++++ 6 files changed, 125 insertions(+) create mode 100644 dlls/winewayland.drv/unixlib.h create mode 100644 dlls/winewayland.drv/waylanddrv.h create mode 100644 dlls/winewayland.drv/waylanddrv_main.c
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 713b281b1bd..1d52f466c41 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -1,6 +1,8 @@ MODULE = winewayland.drv +UNIXLIB = winewayland.so
C_SRCS = \ dllmain.c \ + waylanddrv_main.c \
RC_SRCS = version.rc diff --git a/dlls/winewayland.drv/dllmain.c b/dlls/winewayland.drv/dllmain.c index 7ab3341e61d..89d981a4314 100644 --- a/dlls/winewayland.drv/dllmain.c +++ b/dlls/winewayland.drv/dllmain.c @@ -25,6 +25,10 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) if (reason != DLL_PROCESS_ATTACH) return TRUE;
DisableThreadLibraryCalls(instance); + if (__wine_init_unix_call()) return FALSE; + + if (WAYLANDDRV_UNIX_CALL(init, NULL)) + return FALSE;
return TRUE; } diff --git a/dlls/winewayland.drv/unixlib.h b/dlls/winewayland.drv/unixlib.h new file mode 100644 index 00000000000..427837523e3 --- /dev/null +++ b/dlls/winewayland.drv/unixlib.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WAYLANDDRV_UNIXLIB_H +#define __WINE_WAYLANDDRV_UNIXLIB_H + +#include <stdarg.h> +#include "winternl.h" +#include "wine/unixlib.h" + +enum waylanddrv_unix_func +{ + waylanddrv_unix_func_init, + waylanddrv_unix_func_count, +}; + +#endif /* __WINE_WAYLANDDRV_UNIXLIB_H */ diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h new file mode 100644 index 00000000000..ec656ea87fb --- /dev/null +++ b/dlls/winewayland.drv/waylanddrv.h @@ -0,0 +1,30 @@ +/* + * Wayland driver + * + * Copyright 2020 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WAYLANDDRV_H +#define __WINE_WAYLANDDRV_H + +#ifndef __WINE_CONFIG_H +# error You must include config.h to use this header +#endif + +#include "unixlib.h" + +#endif /* __WINE_WAYLANDDRV_H */ diff --git a/dlls/winewayland.drv/waylanddrv_dll.h b/dlls/winewayland.drv/waylanddrv_dll.h index 556898d44b2..123b6cd5a61 100644 --- a/dlls/winewayland.drv/waylanddrv_dll.h +++ b/dlls/winewayland.drv/waylanddrv_dll.h @@ -25,4 +25,8 @@ #include "windef.h" #include "winbase.h"
+#include "unixlib.h" + +#define WAYLANDDRV_UNIX_CALL(func, params) WINE_UNIX_CALL(waylanddrv_unix_func_ ## func, params) + #endif /* __WINE_WAYLANDDRV_DLL_H */ diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c new file mode 100644 index 00000000000..396beac5828 --- /dev/null +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -0,0 +1,53 @@ +/* + * WAYLANDDRV initialization code + * + * Copyright 2020 Alexandre Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include "ntstatus.h" +#define WIN32_NO_STATUS + +#include "waylanddrv.h" + +static NTSTATUS waylanddrv_unix_init(void *arg) +{ + return 0; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = +{ + waylanddrv_unix_init, +}; + +C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == waylanddrv_unix_func_count); + +#ifdef _WIN64 + +const unixlib_entry_t __wine_unix_call_wow64_funcs[] = +{ + waylanddrv_unix_init, +}; + +C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == waylanddrv_unix_func_count); + +#endif /* _WIN64 */
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Try to connect to the Wayland compositor, and fail driver initialization if we are unable to do so.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- configure | 111 +++++++++++++++++++++++++ configure.ac | 12 +++ dlls/winewayland.drv/Makefile.in | 3 + dlls/winewayland.drv/wayland.c | 41 +++++++++ dlls/winewayland.drv/waylanddrv.h | 14 ++++ dlls/winewayland.drv/waylanddrv_main.c | 2 + include/config.h.in | 3 + tools/gitlab/image.docker | 1 + 8 files changed, 187 insertions(+) create mode 100644 dlls/winewayland.drv/wayland.c
diff --git a/configure b/configure index 210409724f1..ea21eb1fc15 100755 --- a/configure +++ b/configure @@ -702,6 +702,8 @@ INOTIFY_LIBS INOTIFY_CFLAGS PCSCLITE_LIBS PCAP_LIBS +WAYLAND_CLIENT_LIBS +WAYLAND_CLIENT_CFLAGS X_EXTRA_LIBS X_LIBS X_PRE_LIBS @@ -937,6 +939,7 @@ with_unwind with_usb with_v4l2 with_vulkan +with_wayland with_xcomposite with_xcursor with_xfixes @@ -1746,6 +1749,8 @@ ZYDIS_PE_CFLAGS ZYDIS_PE_LIBS XMKMF CPP +WAYLAND_CLIENT_CFLAGS +WAYLAND_CLIENT_LIBS INOTIFY_CFLAGS INOTIFY_LIBS DBUS_CFLAGS @@ -2460,6 +2465,7 @@ Optional Packages: --without-usb do not use the libusb library --without-v4l2 do not use v4l2 (video capture) --without-vulkan do not use Vulkan + --without-wayland do not build the Wayland driver --without-xcomposite do not use the Xcomposite extension --without-xcursor do not use the Xcursor extension --without-xfixes do not use Xfixes for clipboard change notifications @@ -2550,6 +2556,10 @@ Some influential environment variables: Linker flags for the PE zydis, overriding the bundled version XMKMF Path to xmkmf, Makefile generator for X Window System CPP C preprocessor + WAYLAND_CLIENT_CFLAGS + C compiler flags for wayland-client, overriding pkg-config + WAYLAND_CLIENT_LIBS + Linker flags for wayland-client, overriding pkg-config INOTIFY_CFLAGS C compiler flags for libinotify, overriding pkg-config INOTIFY_LIBS @@ -4388,6 +4398,13 @@ then : fi
+# Check whether --with-wayland was given. +if test ${with_wayland+y} +then : + withval=$with_wayland; +fi + + # Check whether --with-xcomposite was given. if test ${with_xcomposite+y} then : @@ -15543,6 +15560,98 @@ enable_winex11_drv=${enable_winex11_drv:-no} fi fi
+if test "x$with_wayland" != "xno" +then + rm -f conftest.err +if ${WAYLAND_CLIENT_CFLAGS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + WAYLAND_CLIENT_CFLAGS=`$PKG_CONFIG --cflags wayland-client 2>conftest.err` +fi +fi + +if ${WAYLAND_CLIENT_LIBS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + WAYLAND_CLIENT_LIBS=`$PKG_CONFIG --libs wayland-client 2>/dev/null` +fi +fi + + +printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-client cflags: $WAYLAND_CLIENT_CFLAGS" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-client libs: $WAYLAND_CLIENT_LIBS" >&5 +if test -s conftest.err; then + printf %s "$as_me:${as_lineno-$LINENO}: wayland-client errors: " >&5 + cat conftest.err >&5 +fi +rm -f conftest.err +ac_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $WAYLAND_CLIENT_CFLAGS" +ac_fn_c_check_header_compile "$LINENO" "wayland-client.h" "ac_cv_header_wayland_client_h" "$ac_includes_default" +if test "x$ac_cv_header_wayland_client_h" = xyes +then : + printf "%s\n" "#define HAVE_WAYLAND_CLIENT_H 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wl_display_connect in -lwayland-client" >&5 +printf %s "checking for wl_display_connect in -lwayland-client... " >&6; } +if test ${ac_cv_lib_wayland_client_wl_display_connect+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lwayland-client $WAYLAND_CLIENT_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char wl_display_connect (); +int +main (void) +{ +return wl_display_connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_wayland_client_wl_display_connect=yes +else $as_nop + ac_cv_lib_wayland_client_wl_display_connect=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_client_wl_display_connect" >&5 +printf "%s\n" "$ac_cv_lib_wayland_client_wl_display_connect" >&6; } +if test "x$ac_cv_lib_wayland_client_wl_display_connect" = xyes +then : + : +else $as_nop + WAYLAND_CLIENT_LIBS="" +fi + +CPPFLAGS=$ac_save_CPPFLAGS + +fi +if test -z "$WAYLAND_CLIENT_LIBS" +then : + case "x$with_wayland" in + x) as_fn_append wine_notices "|Wayland ${notice_platform}development files not found, the Wayland driver won't be supported." ;; + xno) ;; + *) as_fn_error $? "Wayland ${notice_platform}development files not found, the Wayland driver won't be supported. +This is an error since --with-wayland was requested." "$LINENO" 5 ;; +esac +enable_winewayland_drv=${enable_winewayland_drv:-no} +fi + if test "$ac_cv_header_CL_cl_h" = "yes" then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clGetPlatformInfo in -lOpenCL" >&5 @@ -23036,6 +23145,8 @@ X_CFLAGS = $X_CFLAGS X_PRE_LIBS = $X_PRE_LIBS X_LIBS = $X_LIBS X_EXTRA_LIBS = $X_EXTRA_LIBS +WAYLAND_CLIENT_CFLAGS = $WAYLAND_CLIENT_CFLAGS +WAYLAND_CLIENT_LIBS = $WAYLAND_CLIENT_LIBS PCAP_LIBS = $PCAP_LIBS PCSCLITE_LIBS = $PCSCLITE_LIBS INOTIFY_CFLAGS = $INOTIFY_CFLAGS diff --git a/configure.ac b/configure.ac index da9e4c22891..5ff1bb093f4 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,7 @@ AC_ARG_WITH(unwind, AS_HELP_STRING([--without-unwind],[do not use the libunwi AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb library])) AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) +AC_ARG_WITH(wayland, AS_HELP_STRING([--without-wayland],[do not build the Wayland driver])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]), @@ -1335,6 +1336,17 @@ else [enable_winex11_drv]) fi
+if test "x$with_wayland" != "xno" +then + WINE_PACKAGE_FLAGS(WAYLAND_CLIENT,[wayland-client],,,, + [AC_CHECK_HEADERS([wayland-client.h]) + AC_CHECK_LIB(wayland-client,wl_display_connect,[:], + [WAYLAND_CLIENT_LIBS=""],[$WAYLAND_CLIENT_LIBS])]) +fi +WINE_NOTICE_WITH(wayland, [test -z "$WAYLAND_CLIENT_LIBS"], + [Wayland ${notice_platform}development files not found, the Wayland driver won't be supported.], + [enable_winewayland_drv]) + dnl **** Check for OpenCL **** if test "$ac_cv_header_CL_cl_h" = "yes" then diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 1d52f466c41..fc1fe8119ec 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -1,8 +1,11 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so +UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS) +UNIX_LIBS = $(WAYLAND_CLIENT_LIBS)
C_SRCS = \ dllmain.c \ + wayland.c \ waylanddrv_main.c \
RC_SRCS = version.rc diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c new file mode 100644 index 00000000000..9b61427c8aa --- /dev/null +++ b/dlls/winewayland.drv/wayland.c @@ -0,0 +1,41 @@ +/* + * Wayland core handling + * + * Copyright (c) 2020 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include "waylanddrv.h" + +struct wl_display *process_wl_display = NULL; + +/********************************************************************** + * wayland_process_init + * + * Initialise the per process wayland objects. + * + */ +BOOL wayland_process_init(void) +{ + process_wl_display = wl_display_connect(NULL); + return process_wl_display != NULL; +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index ec656ea87fb..3fd8728d81b 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -25,6 +25,20 @@ # error You must include config.h to use this header #endif
+#include <wayland-client.h> + #include "unixlib.h"
+/********************************************************************** + * Globals + */ + +extern struct wl_display *process_wl_display DECLSPEC_HIDDEN; + +/********************************************************************** + * Wayland initialization + */ + +BOOL wayland_process_init(void) DECLSPEC_HIDDEN; + #endif /* __WINE_WAYLANDDRV_H */ diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 396beac5828..d4018683239 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -31,6 +31,8 @@
static NTSTATUS waylanddrv_unix_init(void *arg) { + if (!wayland_process_init()) return STATUS_UNSUCCESSFUL; + return 0; }
diff --git a/include/config.h.in b/include/config.h.in index 44ea547b7ec..2e806157ebd 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -645,6 +645,9 @@ /* Define to 1 if you have the <valgrind/valgrind.h> header file. */ #undef HAVE_VALGRIND_VALGRIND_H
+/* Define to 1 if you have the <wayland-client.h> header file. */ +#undef HAVE_WAYLAND_CLIENT_H + /* Define to 1 if you have the <X11/extensions/shape.h> header file. */ #undef HAVE_X11_EXTENSIONS_SHAPE_H
diff --git a/tools/gitlab/image.docker b/tools/gitlab/image.docker index 0d23a75483b..cf16ed49c95 100644 --- a/tools/gitlab/image.docker +++ b/tools/gitlab/image.docker @@ -37,6 +37,7 @@ RUN export DEBIAN_FRONTEND=noninteractive; \ libusb-1.0-0-dev:amd64 libusb-1.0-0-dev:i386 \ libv4l-dev:amd64 libv4l-dev:i386 \ libvulkan-dev:amd64 libvulkan-dev:i386 \ + libwayland-dev:amd64 libwayland-dev:i386 \ libx11-dev:amd64 libx11-dev:i386 \ libxcomposite-dev:amd64 libxcomposite-dev:i386 \ libxcursor-dev:amd64 libxcursor-dev:i386 \
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Allow passing NULL as the user driver to __wine_set_user_driver(), to set the internal null user driver. This is useful for drivers that may need to tentatively set their own user driver during setup and reset it on failure.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/win32u/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index eb736de272d..5bae77da5f4 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -1241,7 +1241,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version }
driver = malloc( sizeof(*driver) ); - *driver = *funcs; + *driver = funcs ? *funcs : null_user_driver;
#define SET_USER_FUNC(name) \ do { if (!driver->p##name) driver->p##name = nulldrv_##name; } while(0)
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Whenever the Wayland output display state changes (including during initialization), update the monitor information on the Wine side to reflect these changes.
For now all monitors are placed at 0,0 in the monitor space, and only the current mode is reported. These deficiencies will be addressed in upcoming commits.
We currently support a single GPU, and a single monitor for each adapter.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/Makefile.in | 4 +- dlls/winewayland.drv/display.c | 156 +++++++++++++++++++++++++ dlls/winewayland.drv/wayland.c | 94 ++++++++++++++- dlls/winewayland.drv/wayland_output.c | 134 +++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 47 ++++++++ dlls/winewayland.drv/waylanddrv_main.c | 15 ++- 6 files changed, 447 insertions(+), 3 deletions(-) create mode 100644 dlls/winewayland.drv/display.c create mode 100644 dlls/winewayland.drv/wayland_output.c
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index fc1fe8119ec..90124e66163 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -1,11 +1,13 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS) -UNIX_LIBS = $(WAYLAND_CLIENT_LIBS) +UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS)
C_SRCS = \ + display.c \ dllmain.c \ wayland.c \ + wayland_output.c \ waylanddrv_main.c \
RC_SRCS = version.rc diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c new file mode 100644 index 00000000000..74e6450a42b --- /dev/null +++ b/dlls/winewayland.drv/display.c @@ -0,0 +1,156 @@ +/* + * WAYLAND display device functions + * + * Copyright 2020 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include "waylanddrv.h" + +#include "wine/debug.h" + +#include "ntuser.h" + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); + +static BOOL force_display_devices_refresh; + +static void wayland_refresh_display_devices(void) +{ + UINT32 num_path, num_mode; + force_display_devices_refresh = TRUE; + /* Trigger refresh in win32u */ + NtUserGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &num_path, &num_mode); +} + +void wayland_init_display_devices(void) +{ + struct ntuser_thread_info *thread_info = NtUserGetThreadInfo(); + DWORD current_pid = GetCurrentProcessId(); + HWND desktop_hwnd = (HWND)thread_info->top_window; + DWORD desktop_pid = 0; + + if (desktop_hwnd) NtUserGetWindowThread(desktop_hwnd, &desktop_pid); + + /* Refresh devices only from the desktop window process. */ + if (!desktop_pid || current_pid == desktop_pid) + wayland_refresh_display_devices(); +} + +static void wayland_add_device_gpu(const struct gdi_device_manager *device_manager, + void *param) +{ + static const WCHAR wayland_gpuW[] = {'W','a','y','l','a','n','d','G','P','U',0}; + struct gdi_gpu gpu = {0}; + lstrcpyW(gpu.name, wayland_gpuW); + + TRACE("id=0x%s name=%s\n", + wine_dbgstr_longlong(gpu.id), wine_dbgstr_w(gpu.name)); + + device_manager->add_gpu(&gpu, param); +} + +static void wayland_add_device_adapter(const struct gdi_device_manager *device_manager, + void *param, INT output_id) +{ + struct gdi_adapter adapter; + adapter.id = output_id; + adapter.state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; + if (output_id == 0) + adapter.state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE; + + TRACE("id=0x%s state_flags=0x%x\n", + wine_dbgstr_longlong(adapter.id), (UINT)adapter.state_flags); + + device_manager->add_adapter(&adapter, param); +} + +static void wayland_add_device_monitor(const struct gdi_device_manager *device_manager, + void *param, struct wayland_output *output) +{ + struct gdi_monitor monitor = {0}; + + SetRect(&monitor.rc_monitor, 0, 0, + output->current_mode.width, + output->current_mode.height); + + /* We don't have a direct way to get the work area in Wayland. */ + monitor.rc_work = monitor.rc_monitor; + + monitor.state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE; + + TRACE("name=%s rc_monitor=rc_work=%s state_flags=0x%x\n", + output->name, wine_dbgstr_rect(&monitor.rc_monitor), + (UINT)monitor.state_flags); + + device_manager->add_monitor(&monitor, param); +} + +static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW *mode) +{ + mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | + DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; + mode->dmDisplayOrientation = DMDO_DEFAULT; + mode->dmDisplayFlags = 0; + mode->dmBitsPerPel = 32; + mode->dmPelsWidth = output_mode->width; + mode->dmPelsHeight = output_mode->height; + mode->dmDisplayFrequency = output_mode->refresh / 1000; +} + +static void wayland_add_device_mode(const struct gdi_device_manager *device_manager, + void *param, struct wayland_output *output) +{ + DEVMODEW mode; + populate_devmode(&output->current_mode, &mode); + device_manager->add_mode(&mode, param); +} + +/*********************************************************************** + * UpdateDisplayDevices (WAYLAND.@) + */ +BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manager, + BOOL force, void *param) +{ + struct wayland *wayland = process_wayland; + struct wayland_output *output; + INT output_id = 0; + + if (!force && !force_display_devices_refresh) return TRUE; + + TRACE("force=%d force_refresh=%d\n", force, force_display_devices_refresh); + + force_display_devices_refresh = FALSE; + + wayland_add_device_gpu(device_manager, param); + + wl_list_for_each(output, &wayland->output_list, link) + { + if (!output->current_mode.refresh) continue; + wayland_add_device_adapter(device_manager, param, output_id); + wayland_add_device_monitor(device_manager, param, output); + wayland_add_device_mode(device_manager, param, output); + output_id++; + } + + return TRUE; +} diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 9b61427c8aa..104a091ea80 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -26,7 +26,55 @@
#include "waylanddrv.h"
+#include "wine/debug.h" + +#include <stdlib.h> + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); + struct wl_display *process_wl_display = NULL; +struct wayland *process_wayland = NULL; + +/********************************************************************** + * Registry handling + */ + +static void registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t version) +{ + TRACE("interface=%s version=%u id=%u\n", interface, version, id); + + if (strcmp(interface, "wl_output") == 0) + { + if (!wayland_output_create(id, version)) + ERR("Failed to create wayland_output for global id=%u\n", id); + } +} + +static void registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t id) +{ + struct wayland_output *output, *tmp; + + TRACE("id=%u\n", id); + + wl_list_for_each_safe(output, tmp, &process_wayland->output_list, link) + { + if (output->global_id == id) + { + TRACE("removing output->name=%s\n", output->name); + wayland_output_destroy(output); + wayland_init_display_devices(); + return; + } + } +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +};
/********************************************************************** * wayland_process_init @@ -36,6 +84,50 @@ struct wl_display *process_wl_display = NULL; */ BOOL wayland_process_init(void) { + struct wl_display *wl_display_wrapper; + process_wl_display = wl_display_connect(NULL); - return process_wl_display != NULL; + if (!process_wl_display) + return FALSE; + + process_wayland = calloc(1, sizeof(*process_wayland)); + if (!process_wayland) + return FALSE; + + TRACE("process_wayland=%p wl_display=%p\n", process_wayland, process_wl_display); + + if (!(process_wayland->wl_event_queue = wl_display_create_queue(process_wl_display))) + { + ERR("Failed to create event queue\n"); + return FALSE; + } + + if (!(wl_display_wrapper = wl_proxy_create_wrapper(process_wl_display))) + { + ERR("Failed to create proxy wrapper for wl_display\n"); + return FALSE; + } + wl_proxy_set_queue((struct wl_proxy *) wl_display_wrapper, + process_wayland->wl_event_queue); + + process_wayland->wl_registry = wl_display_get_registry(wl_display_wrapper); + wl_proxy_wrapper_destroy(wl_display_wrapper); + if (!process_wayland->wl_registry) + { + ERR("Failed to get to wayland registry\n"); + return FALSE; + } + + wl_list_init(&process_wayland->output_list); + + /* Populate registry */ + wl_registry_add_listener(process_wayland->wl_registry, ®istry_listener, + process_wayland); + + /* We need two roundtrips. One to get and bind globals, one to handle all + * initial events produced from registering the globals. */ + wl_display_roundtrip_queue(process_wl_display, process_wayland->wl_event_queue); + wl_display_roundtrip_queue(process_wl_display, process_wayland->wl_event_queue); + + return TRUE; } diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c new file mode 100644 index 00000000000..9f9dfc06cb4 --- /dev/null +++ b/dlls/winewayland.drv/wayland_output.c @@ -0,0 +1,134 @@ +/* + * Wayland output handling + * + * Copyright (c) 2020 Alexandros Frantzis for Collabora Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include "waylanddrv.h" + +#include "wine/debug.h" + +#include <stdlib.h> + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); + +static const int32_t default_refresh = 60000; +static uint32_t next_output_id = 0; + +/********************************************************************** + * Output handling + */ + +static void output_handle_geometry(void *data, struct wl_output *wl_output, + int32_t x, int32_t y, + int32_t physical_width, int32_t physical_height, + int32_t subpixel, + const char *make, const char *model, + int32_t output_transform) +{ +} + +static void output_handle_mode(void *data, struct wl_output *wl_output, + uint32_t flags, int32_t width, int32_t height, + int32_t refresh) +{ + struct wayland_output *output = data; + + if (!(flags & WL_OUTPUT_MODE_CURRENT)) return; + + /* Windows apps don't expect a zero refresh rate, so use a default value. */ + if (refresh == 0) refresh = default_refresh; + + output->current_mode.width = width; + output->current_mode.height = width; + output->current_mode.refresh = refresh; +} + +static void output_handle_done(void *data, struct wl_output *wl_output) +{ + struct wayland_output *output = data; + + TRACE("name=%s mode=%dx%d\n", + output->name, output->current_mode.width, output->current_mode.height); + + wayland_init_display_devices(); +} + +static void output_handle_scale(void *data, struct wl_output *wl_output, + int32_t scale) +{ +} + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, + output_handle_done, + output_handle_scale +}; + +/********************************************************************** + * wayland_output_create + * + * Creates a wayland_output and adds it to the output list. + */ +BOOL wayland_output_create(uint32_t id, uint32_t version) +{ + struct wayland_output *output = calloc(1, sizeof(*output)); + + if (!output) + { + ERR("Couldn't allocate space for wayland_output\n"); + goto err; + } + + output->wl_output = wl_registry_bind(process_wayland->wl_registry, id, + &wl_output_interface, + version < 2 ? version : 2); + output->global_id = id; + wl_output_add_listener(output->wl_output, &output_listener, output); + + wl_list_init(&output->link); + + snprintf(output->name, sizeof(output->name), "WaylandOutput%d", + next_output_id++); + + wl_list_insert(process_wayland->output_list.prev, &output->link); + + return TRUE; + +err: + if (output) wayland_output_destroy(output); + return FALSE; +} + +/********************************************************************** + * wayland_output_destroy + * + * Destroys a wayland_output. + */ +void wayland_output_destroy(struct wayland_output *output) +{ + wl_list_remove(&output->link); + wl_output_destroy(output->wl_output); + free(output); +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 3fd8728d81b..768e22f2caf 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -27,6 +27,10 @@
#include <wayland-client.h>
+#include "windef.h" +#include "winbase.h" +#include "wine/gdi_driver.h" + #include "unixlib.h"
/********************************************************************** @@ -34,11 +38,54 @@ */
extern struct wl_display *process_wl_display DECLSPEC_HIDDEN; +extern struct wayland *process_wayland DECLSPEC_HIDDEN; + +/********************************************************************** + * Definitions for wayland types + */ + +struct wayland +{ + struct wl_event_queue *wl_event_queue; + struct wl_registry *wl_registry; + struct wl_list output_list; +}; + +struct wayland_output_mode +{ + int32_t width; + int32_t height; + int32_t refresh; +}; + +struct wayland_output +{ + struct wl_list link; + struct wl_output *wl_output; + struct wayland_output_mode current_mode; + char name[20]; + uint32_t global_id; +};
/********************************************************************** * Wayland initialization */
BOOL wayland_process_init(void) DECLSPEC_HIDDEN; +void wayland_init_display_devices(void) DECLSPEC_HIDDEN; + +/********************************************************************** + * Wayland output + */ + +BOOL wayland_output_create(uint32_t id, uint32_t version) DECLSPEC_HIDDEN; +void wayland_output_destroy(struct wayland_output *output) DECLSPEC_HIDDEN; + +/********************************************************************** + * USER driver functions + */ + +BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manager, + BOOL force, void *param) DECLSPEC_HIDDEN;
#endif /* __WINE_WAYLANDDRV_H */ diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index d4018683239..a9297edc500 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -29,11 +29,24 @@
#include "waylanddrv.h"
+static const struct user_driver_funcs waylanddrv_funcs = +{ + .pUpdateDisplayDevices = WAYLAND_UpdateDisplayDevices, +}; + static NTSTATUS waylanddrv_unix_init(void *arg) { - if (!wayland_process_init()) return STATUS_UNSUCCESSFUL; + /* Set the user driver functions now so that they are available during + * our initialization. We clear them on error. */ + __wine_set_user_driver(&waylanddrv_funcs, WINE_GDI_DRIVER_VERSION); + + if (!wayland_process_init()) goto err;
return 0; + +err: + __wine_set_user_driver(NULL, WINE_GDI_DRIVER_VERSION); + return STATUS_UNSUCCESSFUL; }
const unixlib_entry_t __wine_unix_call_funcs[] =
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/display.c | 23 +++++--- dlls/winewayland.drv/wayland_output.c | 81 ++++++++++++++++++++++++--- dlls/winewayland.drv/waylanddrv.h | 4 +- 3 files changed, 91 insertions(+), 17 deletions(-)
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index 74e6450a42b..991de498aa5 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -90,8 +90,8 @@ static void wayland_add_device_monitor(const struct gdi_device_manager *device_m struct gdi_monitor monitor = {0};
SetRect(&monitor.rc_monitor, 0, 0, - output->current_mode.width, - output->current_mode.height); + output->current_mode->width, + output->current_mode->height);
/* We don't have a direct way to get the work area in Wayland. */ monitor.rc_work = monitor.rc_monitor; @@ -117,12 +117,17 @@ static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW * mode->dmDisplayFrequency = output_mode->refresh / 1000; }
-static void wayland_add_device_mode(const struct gdi_device_manager *device_manager, - void *param, struct wayland_output *output) +static void wayland_add_device_modes(const struct gdi_device_manager *device_manager, + void *param, struct wayland_output *output) { - DEVMODEW mode; - populate_devmode(&output->current_mode, &mode); - device_manager->add_mode(&mode, param); + struct wayland_output_mode *output_mode; + + wl_list_for_each(output_mode, &output->mode_list, link) + { + DEVMODEW mode; + populate_devmode(output_mode, &mode); + device_manager->add_mode(&mode, param); + } }
/*********************************************************************** @@ -145,10 +150,10 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage
wl_list_for_each(output, &wayland->output_list, link) { - if (!output->current_mode.refresh) continue; + if (!output->current_mode) continue; wayland_add_device_adapter(device_manager, param, output_id); wayland_add_device_monitor(device_manager, param, output); - wayland_add_device_mode(device_manager, param, output); + wayland_add_device_modes(device_manager, param, output); output_id++; }
diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c index 9f9dfc06cb4..975953536d5 100644 --- a/dlls/winewayland.drv/wayland_output.c +++ b/dlls/winewayland.drv/wayland_output.c @@ -39,6 +39,61 @@ static uint32_t next_output_id = 0; * Output handling */
+/* Compare mode with the set of provided mode parameters and return -1 if the + * mode compares less than the parameters, 0 if the mode compares equal to the + * parameters, and 1 if the mode compares greater than the parameters. + * + * The comparison is based on comparing the width, height and refresh + * in that order. + */ +static int wayland_output_mode_cmp(struct wayland_output_mode *mode, + int32_t width, int32_t height, + int32_t refresh) +{ + if (mode->width < width) return -1; + if (mode->width > width) return 1; + if (mode->height < height) return -1; + if (mode->height > height) return 1; + if (mode->refresh < refresh) return -1; + if (mode->refresh > refresh) return 1; + return 0; +} + +static void wayland_output_add_mode(struct wayland_output *output, + int32_t width, int32_t height, + int32_t refresh, BOOL current) +{ + struct wayland_output_mode *mode; + struct wl_list *insert_after_link = output->mode_list.prev; + + /* Update mode if it's already in list, otherwise find the insertion point + * to maintain the sorted order. */ + wl_list_for_each(mode, &output->mode_list, link) + { + int cmp = wayland_output_mode_cmp(mode, width, height, refresh); + if (cmp == 0) /* mode == new */ + { + if (current) output->current_mode = mode; + return; + } + else if (cmp == 1) /* mode > new */ + { + insert_after_link = mode->link.prev; + break; + } + } + + mode = calloc(1, sizeof(*mode)); + + mode->width = width; + mode->height = height; + mode->refresh = refresh; + + if (current) output->current_mode = mode; + + wl_list_insert(insert_after_link, &mode->link); +} + static void output_handle_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, @@ -54,22 +109,26 @@ static void output_handle_mode(void *data, struct wl_output *wl_output, { struct wayland_output *output = data;
- if (!(flags & WL_OUTPUT_MODE_CURRENT)) return; - /* Windows apps don't expect a zero refresh rate, so use a default value. */ if (refresh == 0) refresh = default_refresh;
- output->current_mode.width = width; - output->current_mode.height = width; - output->current_mode.refresh = refresh; + wayland_output_add_mode(output, width, height, refresh, + (flags & WL_OUTPUT_MODE_CURRENT)); }
static void output_handle_done(void *data, struct wl_output *wl_output) { struct wayland_output *output = data; + struct wayland_output_mode *mode;
- TRACE("name=%s mode=%dx%d\n", - output->name, output->current_mode.width, output->current_mode.height); + TRACE("name=%s\n", output->name); + + wl_list_for_each(mode, &output->mode_list, link) + { + TRACE("mode %dx%d @ %d %s\n", + mode->width, mode->height, mode->refresh, + output->current_mode == mode ? "*" : ""); + }
wayland_init_display_devices(); } @@ -108,6 +167,7 @@ BOOL wayland_output_create(uint32_t id, uint32_t version) wl_output_add_listener(output->wl_output, &output_listener, output);
wl_list_init(&output->link); + wl_list_init(&output->mode_list);
snprintf(output->name, sizeof(output->name), "WaylandOutput%d", next_output_id++); @@ -128,6 +188,13 @@ err: */ void wayland_output_destroy(struct wayland_output *output) { + struct wayland_output_mode *mode, *tmp; + + wl_list_for_each_safe(mode, tmp, &output->mode_list, link) + { + wl_list_remove(&mode->link); + free(mode); + } wl_list_remove(&output->link); wl_output_destroy(output->wl_output); free(output); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 768e22f2caf..5154d953417 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -53,6 +53,7 @@ struct wayland
struct wayland_output_mode { + struct wl_list link; int32_t width; int32_t height; int32_t refresh; @@ -62,7 +63,8 @@ struct wayland_output { struct wl_list link; struct wl_output *wl_output; - struct wayland_output_mode current_mode; + struct wl_list mode_list; + struct wayland_output_mode *current_mode; char name[20]; uint32_t global_id; };