From d5a0610ea26c7086301db1c397a4d5b48ad469b4 Mon Sep 17 00:00:00 2001
From: Vaxry <43317083+vaxerski@users.noreply.github.com>
Date: Thu, 27 Oct 2022 11:26:35 +0100
Subject: [PATCH] No xwayland overhaul (#920)

---
 .github/workflows/ci.yaml        |  32 ++++---
 CMakeLists.txt                   |  31 +++++--
 src/events/Misc.cpp              |   2 +
 src/helpers/XWaylandStubs.hpp    | 152 +++++++++++++++++++++++++++++++
 src/includes.hpp                 |   9 +-
 src/managers/XWaylandManager.cpp |  30 +++---
 6 files changed, 217 insertions(+), 39 deletions(-)
 create mode 100644 src/helpers/XWaylandStubs.hpp

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 77c9c48b..def12910 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -62,7 +62,7 @@ jobs:
         run: |
           sed -i 's/SigLevel    = Required DatabaseOptional/SigLevel    = Optional TrustAll/' /etc/pacman.conf
           pacman --noconfirm --noprogressbar -Syyu
-          pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
+          pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd cmake 
       - name: Checkout Hyprland
         uses: actions/checkout@v3
         with:
@@ -73,13 +73,23 @@ jobs:
             -Ddefault_library=static
       - name: Compile
         run: ninja -C obj-x86_64-pc-linux-gnu
-#       - name: Compress artifacts
-#         run: |
-#           mkdir x86_64-pc-linux-gnu
-#           DESTDIR=$PWD/x86_64-pc-linux-gnu meson install -C obj-x86_64-pc-linux-gnu --tags runtime
-#           tar -cvf x86_64-pc-linux-gnu.tar.xz x86_64-pc-linux-gnu
-#       - name: Upload artifacts
-#         uses: actions/upload-artifact@v3
-#         with:
-#           name: Build artifacts (x86_64-pc-linux-gnu)
-#           path: x86_64-pc-linux-gnu.tar.xz
+
+  noxwayland:
+    name: "Build Hyprland in pure Wayland (Arch)"
+    runs-on: ubuntu-latest
+    container:
+      image: archlinux
+    steps:
+      - name: Download dependencies
+        run: |
+          sed -i 's/SigLevel    = Required DatabaseOptional/SigLevel    = Optional TrustAll/' /etc/pacman.conf
+          pacman --noconfirm --noprogressbar -Syyu
+          pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
+      - name: Checkout Hyprland
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+      - name: Configure
+        run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja 
+      - name: Compile
+        run: make config && make release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index da311fde..8aed8896 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ project(Hyprland
 
 set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
 
-message(STATUS "Configuring Hyprland!")
+message(STATUS "Gathering git info")
 
 # Get git info
 # hash and branch
@@ -35,14 +35,25 @@ execute_process(
 #
 #
 
+IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
+    message(STATUS "Configuring Hyprland in Debug with CMake")
+    add_definitions( -DHYPRLAND_DEBUG )
+ELSE()
+    add_compile_options( -O3 )
+    message(STATUS "Configuring Hyprland in Release with CMake")
+ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
+
 include_directories(. PRIVATE "subprojects/wlroots/include/")
 include_directories(. PRIVATE "subprojects/wlroots/build/include/")
 add_compile_options(-std=c++23 -DWLR_USE_UNSTABLE )
 add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing)
+
+message(STATUS "Checking deps...")
+
 find_package(Threads REQUIRED)
 
 find_package(PkgConfig REQUIRED)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon libinput xcb) # we do not check for wlroots, as we provide it ourselves
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon libinput) # we do not check for wlroots, as we provide it ourselves
 
 file(GLOB_RECURSE SRCFILES "src/*.cpp")
 
@@ -56,15 +67,11 @@ ENDIF(LEGACY_RENDERER MATCHES true)
 IF(NO_XWAYLAND MATCHES true)
     message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
     add_definitions( -DNO_XWAYLAND )
-ENDIF(NO_XWAYLAND MATCHES true)
-
-IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
-    message(STATUS "Configuring Hyprland in Debug with CMake!")
-    add_definitions( -DHYPRLAND_DEBUG )
 ELSE()
-    add_compile_options( -O3 )
-    message(STATUS "Configuring Hyprland in Release with CMake!")
-ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
+    message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
+    pkg_check_modules(xcbdep REQUIRED xcb)
+    target_link_libraries(Hyprland xcb)
+ENDIF(NO_XWAYLAND MATCHES true)
 
 target_compile_definitions(Hyprland PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
 target_compile_definitions(Hyprland PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"")
@@ -77,6 +84,8 @@ set(CPACK_PROJECT_NAME ${PROJECT_NAME})
 set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
 include(CPack)
 
+message(STATUS "Setting link libraries")
+
 target_link_libraries(Hyprland PkgConfig::deps)
 
 target_link_libraries(Hyprland
@@ -90,6 +99,8 @@ target_link_libraries(Hyprland
 )
 
 IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
+    message(STATUS "Setting debug flags")
+
     SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -no-pie -fno-builtin")
     SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg -no-pie -fno-builtin")
     SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg -no-pie -fno-builtin")
diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp
index 8e02579e..1edea5ba 100644
--- a/src/events/Misc.cpp
+++ b/src/events/Misc.cpp
@@ -45,6 +45,7 @@ void Events::listener_requestSetSel(wl_listener* listener, void* data) {
 }
 
 void Events::listener_readyXWayland(wl_listener* listener, void* data) {
+#ifndef NO_XWAYLAND
     const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
     const auto ERR = xcb_connection_has_error(XCBCONNECTION);
     if (ERR) {
@@ -72,6 +73,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
     }
 
     xcb_disconnect(XCBCONNECTION);
+#endif
 }
 
 void Events::listener_requestDrag(wl_listener* listener, void* data) {
diff --git a/src/helpers/XWaylandStubs.hpp b/src/helpers/XWaylandStubs.hpp
new file mode 100644
index 00000000..a0b2a358
--- /dev/null
+++ b/src/helpers/XWaylandStubs.hpp
@@ -0,0 +1,152 @@
+#pragma once
+
+#include <wayland-server.h>
+
+typedef unsigned int xcb_atom_t;
+struct xcb_icccm_wm_hints_t;
+typedef struct {
+    /** User specified flags */
+    uint32_t flags;
+    /** User-specified position */
+    int32_t x, y;
+    /** User-specified size */
+    int32_t width, height;
+    /** Program-specified minimum size */
+    int32_t min_width, min_height;
+    /** Program-specified maximum size */
+    int32_t max_width, max_height;
+    /** Program-specified resize increments */
+    int32_t width_inc, height_inc;
+    /** Program-specified minimum aspect ratios */
+    int32_t min_aspect_num, min_aspect_den;
+    /** Program-specified maximum aspect ratios */
+    int32_t max_aspect_num, max_aspect_den;
+    /** Program-specified base size */
+    int32_t base_width, base_height;
+    /** Program-specified window gravity */
+    uint32_t win_gravity;
+} xcb_size_hints_t;
+typedef unsigned int xcb_window_t;
+
+typedef enum xcb_stack_mode_t {
+    XCB_STACK_MODE_ABOVE = 0,
+    XCB_STACK_MODE_BELOW = 1,
+    XCB_STACK_MODE_TOP_IF = 2,
+    XCB_STACK_MODE_BOTTOM_IF = 3,
+    XCB_STACK_MODE_OPPOSITE = 4
+} xcb_stack_mode_t;
+
+struct wlr_xwayland {
+    struct wlr_xwayland_server *server;
+	struct wlr_xwm *xwm;
+	struct wlr_xwayland_cursor *cursor;
+
+	const char *display_name;
+
+	struct wl_display *wl_display;
+	struct wlr_compositor *compositor;
+	struct wlr_seat *seat;
+
+	void *data;
+};
+
+struct wlr_xwayland_surface {
+    xcb_window_t window_id;
+    struct wlr_xwm *xwm;
+    uint32_t surface_id;
+
+    struct wl_list link;
+    struct wl_list stack_link;
+    struct wl_list unpaired_link;
+
+    struct wlr_surface *surface;
+    int16_t x, y;
+    uint16_t width, height;
+    uint16_t saved_width, saved_height;
+    bool override_redirect;
+    bool mapped;
+
+    char *title;
+    char *_class;
+    char *instance;
+    char *role;
+    char *startup_id;
+    pid_t pid;
+    bool has_utf8_title;
+
+    struct wl_list children;  // wlr_xwayland_surface::parent_link
+    struct wlr_xwayland_surface *parent;
+    struct wl_list parent_link;  // wlr_xwayland_surface::children
+
+    xcb_atom_t *window_type;
+    size_t window_type_len;
+
+    xcb_atom_t *protocols;
+    size_t protocols_len;
+
+    uint32_t decorations;
+    xcb_icccm_wm_hints_t *hints;
+    xcb_size_hints_t *size_hints;
+
+    bool pinging;
+    struct wl_event_source *ping_timer;
+
+    // _NET_WM_STATE
+    bool modal;
+    bool fullscreen;
+    bool maximized_vert, maximized_horz;
+    bool minimized;
+
+    bool has_alpha;
+
+    struct {
+        struct wl_signal destroy;
+        struct wl_signal request_configure;
+        struct wl_signal request_move;
+        struct wl_signal request_resize;
+        struct wl_signal request_minimize;
+        struct wl_signal request_maximize;
+        struct wl_signal request_fullscreen;
+        struct wl_signal request_activate;
+
+        struct wl_signal map;
+        struct wl_signal unmap;
+        struct wl_signal set_title;
+        struct wl_signal set_class;
+        struct wl_signal set_role;
+        struct wl_signal set_parent;
+        struct wl_signal set_pid;
+        struct wl_signal set_startup_id;
+        struct wl_signal set_window_type;
+        struct wl_signal set_hints;
+        struct wl_signal set_decorations;
+        struct wl_signal set_override_redirect;
+        struct wl_signal set_geometry;
+        struct wl_signal ping_timeout;
+    } events;
+};
+
+struct wlr_xwayland_surface_configure_event {
+    struct wlr_xwayland_surface *surface;
+    int16_t x, y;
+    uint16_t width, height;
+    uint16_t mask;  // xcb_config_window_t
+};
+
+inline void wlr_xwayland_destroy(wlr_xwayland*) { }
+
+inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) { }
+
+inline bool wlr_surface_is_xwayland_surface(void*) { return false; }
+
+inline void wlr_xwayland_surface_activate(wlr_xwayland_surface*, bool) { }
+
+inline void wlr_xwayland_surface_restack(wlr_xwayland_surface*, int, xcb_stack_mode_t) { }
+
+inline wlr_xwayland_surface* wlr_xwayland_surface_from_wlr_surface(void*) { return nullptr; }
+
+inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) { }
+
+inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) { }
+
+inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) {}
diff --git a/src/includes.hpp b/src/includes.hpp
index 55e8282b..607eb539 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -22,7 +22,6 @@
 #include <filesystem>
 #include <climits>
 
-
 #if true
 // wlroots uses dumb-ass shit that makes it not compile on C++, let's fix that.
 // https://github.com/swaywm/wlroots/issues/682
@@ -80,13 +79,11 @@ extern "C" {
 #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
 #include <wlr/types/wlr_idle_inhibit_v1.h>
 #include <wlr/util/log.h>
-#include <wlr/xwayland.h>
 #include <wlr/util/region.h>
 #include <wlr/types/wlr_tablet_pad.h>
 #include <wlr/types/wlr_tablet_tool.h>
 #include <wlr/types/wlr_tablet_v2.h>
 #include <xkbcommon/xkbcommon.h>
-#include <X11/Xproto.h>
 #include <wlr/render/egl.h>
 #include <wlr/render/gles2.h>
 #include <wlr/render/wlr_texture.h>
@@ -102,6 +99,11 @@ extern "C" {
 #include <wlr/types/wlr_text_input_v3.h>
 #include <wlr/types/wlr_touch.h>
 #include <wlr/types/wlr_switch.h>
+
+#ifndef NO_XWAYLAND
+#include <wlr/xwayland.h>
+#include <X11/Xproto.h>
+#endif
 }
 
 #undef delete
@@ -122,6 +124,7 @@ extern "C" {
 
 #ifdef NO_XWAYLAND
 #define XWAYLAND false
+#include "helpers/XWaylandStubs.hpp"
 #else
 #define XWAYLAND true
 #endif
diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp
index 4a0b397d..89bb6871 100644
--- a/src/managers/XWaylandManager.cpp
+++ b/src/managers/XWaylandManager.cpp
@@ -3,23 +3,23 @@
 #include "../events/Events.hpp"
 
 CHyprXWaylandManager::CHyprXWaylandManager() {
-    if (XWAYLAND) {
-        m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1);
+#ifndef NO_XWAYLAND
+    m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1);
 
-        if (!m_sWLRXWayland) {
-            Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!");
-            return;
-        }
-
-        addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager");
-        addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager");
-
-        setenv("DISPLAY", m_sWLRXWayland->display_name, 1);
-
-        Debug::log(LOG, "CHyprXWaylandManager started on display %s", m_sWLRXWayland->display_name);
-    } else {
-        unsetenv("DISPLAY"); // unset DISPLAY so that X11 apps do not try to start on a different/invalid DISPLAY
+    if (!m_sWLRXWayland) {
+        Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!");
+        return;
     }
+
+    addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager");
+    addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager");
+
+    setenv("DISPLAY", m_sWLRXWayland->display_name, 1);
+
+    Debug::log(LOG, "CHyprXWaylandManager started on display %s", m_sWLRXWayland->display_name);
+#else
+    unsetenv("DISPLAY");  // unset DISPLAY so that X11 apps do not try to start on a different/invalid DISPLAY
+#endif
 }
 
 CHyprXWaylandManager::~CHyprXWaylandManager() {