diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 9af3362..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,3 +0,0 @@ -Coding conventions: -- Use `clang-format` on all C and C++ sources before committing. -- In `CMakeLists.txt`, indent with four spaces. Tabs may be used for C++ files as per .clang-format. diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index f8ffe0b..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -cmake_minimum_required(VERSION 3.12) - -project(lunarwm VERSION 0.0.1 LANGUAGES C CXX) - -execute_process(COMMAND pkg-config --variable=pkgdatadir wayland-protocols - OUTPUT_VARIABLE WAYLAND_PROTOCOLS - OUTPUT_STRIP_TRAILING_WHITESPACE) -execute_process(COMMAND pkg-config --variable=wayland_scanner wayland-scanner - OUTPUT_VARIABLE WAYLAND_SCANNER - OUTPUT_STRIP_TRAILING_WHITESPACE) - -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-protocol.h - COMMAND ${WAYLAND_SCANNER} server-header - ${WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml - ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-protocol.h - MAIN_DEPENDENCY ${WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml - COMMENT "Generating xdg-shell-protocol.h" -) - -add_custom_target(xdg_shell_proto - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-protocol.h -) - -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -add_compile_options(-Wall -Wextra -Wno-missing-field-initializers) - -add_compile_definitions( - XR_USE_PLATFORM_XLIB - XR_USE_GRAPHICS_API_OPENGL - WLR_USE_UNSTABLE -) - - -list(INSERT CMAKE_MODULE_PATH 0 - ${CMAKE_CURRENT_SOURCE_DIR}/cmake -) - -find_package(OpenGL REQUIRED) -find_package(OpenXR REQUIRED) -find_package(glm REQUIRED) -find_package(PkgConfig REQUIRED) -pkg_check_modules(Wlroots REQUIRED wlroots-0.19) -pkg_check_modules(X11 REQUIRED x11) -pkg_check_modules(wayland REQUIRED wayland-server wayland-protocols) - -include_directories( - ${wayland_INCLUDE_DIRS} - ${X11_INCLUDE_DIRS} - ${GLM_INCLUDE_DIRS} - ${Wlroots_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} -) - -set(SOURCES - src/wlr/backend.cpp - src/wlr/output.cpp - src/wlr/openxr_gl.cpp - - src/compositor.cpp - src/main.cpp - - ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-protocol.h -) - -add_executable(${PROJECT_NAME} ${SOURCES}) - -target_link_libraries(${PROJECT_NAME} - OpenGL::GL - openxr_loader - ${wayland_LIBRARIES} - ${X11_LIBRARIES} - ${GLM_LIBRARIES} - ${Wlroots_LIBRARIES} -) - diff --git a/cmake/FindWlroots.cmake b/cmake/FindWlroots.cmake deleted file mode 100644 index 07797b5..0000000 --- a/cmake/FindWlroots.cmake +++ /dev/null @@ -1,10 +0,0 @@ -find_package(PkgConfig) -pkg_check_modules(PC_WLR QUIET wlroots) -find_path(WLR_INCLUDE_DIRS NAMES wlr/config.h HINTS ${PC_WLR_INCLUDE_DIRS}) -find_library(WLR_LIBRARIES NAMES wlroots HINTS ${PC_WLR_LIBRARY_DIRS}) - -set(WLR_DEFINITIONS ${PC_WLR_CFLAGS_OTHER}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(wlr DEFAULT_MSG WLR_LIBRARIES WLR_INCLUDE_DIRS) -mark_as_advanced(WLR_LIBRARIES WLR_INCLUDE_DIRS) diff --git a/protocol/wlr-layer-shell-unstable-v1.xml b/protocol/wlr-layer-shell-unstable-v1.xml deleted file mode 100644 index e9f27e4..0000000 --- a/protocol/wlr-layer-shell-unstable-v1.xml +++ /dev/null @@ -1,407 +0,0 @@ - - - - Copyright © 2017 Drew DeVault - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - Clients can use this interface to assign the surface_layer role to - wl_surfaces. Such surfaces are assigned to a "layer" of the output and - rendered with a defined z-depth respective to each other. They may also be - anchored to the edges and corners of a screen and specify input handling - semantics. This interface should be suitable for the implementation of - many desktop shell components, and a broad number of other applications - that interact with the desktop. - - - - - Create a layer surface for an existing surface. This assigns the role of - layer_surface, or raises a protocol error if another role is already - assigned. - - Creating a layer surface from a wl_surface which has a buffer attached - or committed is a client error, and any attempts by a client to attach - or manipulate a buffer prior to the first layer_surface.configure call - must also be treated as errors. - - After creating a layer_surface object and setting it up, the client - must perform an initial commit without any buffer attached. - The compositor will reply with a layer_surface.configure event. - The client must acknowledge it and is then allowed to attach a buffer - to map the surface. - - You may pass NULL for output to allow the compositor to decide which - output to use. Generally this will be the one that the user most - recently interacted with. - - Clients can specify a namespace that defines the purpose of the layer - surface. - - - - - - - - - - - - - - - - - These values indicate which layers a surface can be rendered in. They - are ordered by z depth, bottom-most first. Traditional shell surfaces - will typically be rendered between the bottom and top layers. - Fullscreen shell surfaces are typically rendered at the top layer. - Multiple surfaces can share a single layer, and ordering within a - single layer is undefined. - - - - - - - - - - - - - This request indicates that the client will not use the layer_shell - object any more. Objects that have been created through this instance - are not affected. - - - - - - - An interface that may be implemented by a wl_surface, for surfaces that - are designed to be rendered as a layer of a stacked desktop-like - environment. - - Layer surface state (layer, size, anchor, exclusive zone, - margin, interactivity) is double-buffered, and will be applied at the - time wl_surface.commit of the corresponding wl_surface is called. - - Attaching a null buffer to a layer surface unmaps it. - - Unmapping a layer_surface means that the surface cannot be shown by the - compositor until it is explicitly mapped again. The layer_surface - returns to the state it had right after layer_shell.get_layer_surface. - The client can re-map the surface by performing a commit without any - buffer attached, waiting for a configure event and handling it as usual. - - - - - Sets the size of the surface in surface-local coordinates. The - compositor will display the surface centered with respect to its - anchors. - - If you pass 0 for either value, the compositor will assign it and - inform you of the assignment in the configure event. You must set your - anchor to opposite edges in the dimensions you omit; not doing so is a - protocol error. Both values are 0 by default. - - Size is double-buffered, see wl_surface.commit. - - - - - - - - Requests that the compositor anchor the surface to the specified edges - and corners. If two orthogonal edges are specified (e.g. 'top' and - 'left'), then the anchor point will be the intersection of the edges - (e.g. the top left corner of the output); otherwise the anchor point - will be centered on that edge, or in the center if none is specified. - - Anchor is double-buffered, see wl_surface.commit. - - - - - - - Requests that the compositor avoids occluding an area with other - surfaces. The compositor's use of this information is - implementation-dependent - do not assume that this region will not - actually be occluded. - - A positive value is only meaningful if the surface is anchored to one - edge or an edge and both perpendicular edges. If the surface is not - anchored, anchored to only two perpendicular edges (a corner), anchored - to only two parallel edges or anchored to all edges, a positive value - will be treated the same as zero. - - A positive zone is the distance from the edge in surface-local - coordinates to consider exclusive. - - Surfaces that do not wish to have an exclusive zone may instead specify - how they should interact with surfaces that do. If set to zero, the - surface indicates that it would like to be moved to avoid occluding - surfaces with a positive exclusive zone. If set to -1, the surface - indicates that it would not like to be moved to accommodate for other - surfaces, and the compositor should extend it all the way to the edges - it is anchored to. - - For example, a panel might set its exclusive zone to 10, so that - maximized shell surfaces are not shown on top of it. A notification - might set its exclusive zone to 0, so that it is moved to avoid - occluding the panel, but shell surfaces are shown underneath it. A - wallpaper or lock screen might set their exclusive zone to -1, so that - they stretch below or over the panel. - - The default value is 0. - - Exclusive zone is double-buffered, see wl_surface.commit. - - - - - - - Requests that the surface be placed some distance away from the anchor - point on the output, in surface-local coordinates. Setting this value - for edges you are not anchored to has no effect. - - The exclusive zone includes the margin. - - Margin is double-buffered, see wl_surface.commit. - - - - - - - - - - Types of keyboard interaction possible for layer shell surfaces. The - rationale for this is twofold: (1) some applications are not interested - in keyboard events and not allowing them to be focused can improve the - desktop experience; (2) some applications will want to take exclusive - keyboard focus. - - - - - This value indicates that this surface is not interested in keyboard - events and the compositor should never assign it the keyboard focus. - - This is the default value, set for newly created layer shell surfaces. - - This is useful for e.g. desktop widgets that display information or - only have interaction with non-keyboard input devices. - - - - - Request exclusive keyboard focus if this surface is above the shell surface layer. - - For the top and overlay layers, the seat will always give - exclusive keyboard focus to the top-most layer which has keyboard - interactivity set to exclusive. If this layer contains multiple - surfaces with keyboard interactivity set to exclusive, the compositor - determines the one receiving keyboard events in an implementation- - defined manner. In this case, no guarantee is made when this surface - will receive keyboard focus (if ever). - - For the bottom and background layers, the compositor is allowed to use - normal focus semantics. - - This setting is mainly intended for applications that need to ensure - they receive all keyboard events, such as a lock screen or a password - prompt. - - - - - This requests the compositor to allow this surface to be focused and - unfocused by the user in an implementation-defined manner. The user - should be able to unfocus this surface even regardless of the layer - it is on. - - Typically, the compositor will want to use its normal mechanism to - manage keyboard focus between layer shell surfaces with this setting - and regular toplevels on the desktop layer (e.g. click to focus). - Nevertheless, it is possible for a compositor to require a special - interaction to focus or unfocus layer shell surfaces (e.g. requiring - a click even if focus follows the mouse normally, or providing a - keybinding to switch focus between layers). - - This setting is mainly intended for desktop shell components (e.g. - panels) that allow keyboard interaction. Using this option can allow - implementing a desktop shell that can be fully usable without the - mouse. - - - - - - - Set how keyboard events are delivered to this surface. By default, - layer shell surfaces do not receive keyboard events; this request can - be used to change this. - - This setting is inherited by child surfaces set by the get_popup - request. - - Layer surfaces receive pointer, touch, and tablet events normally. If - you do not want to receive them, set the input region on your surface - to an empty region. - - Keyboard interactivity is double-buffered, see wl_surface.commit. - - - - - - - This assigns an xdg_popup's parent to this layer_surface. This popup - should have been created via xdg_surface::get_popup with the parent set - to NULL, and this request must be invoked before committing the popup's - initial state. - - See the documentation of xdg_popup for more details about what an - xdg_popup is and how it is used. - - - - - - - When a configure event is received, if a client commits the - surface in response to the configure event, then the client - must make an ack_configure request sometime before the commit - request, passing along the serial of the configure event. - - If the client receives multiple configure events before it - can respond to one, it only has to ack the last configure event. - - A client is not required to commit immediately after sending - an ack_configure request - it may even ack_configure several times - before its next surface commit. - - A client may send multiple ack_configure requests before committing, but - only the last request sent before a commit indicates which configure - event the client really is responding to. - - - - - - - This request destroys the layer surface. - - - - - - The configure event asks the client to resize its surface. - - Clients should arrange their surface for the new states, and then send - an ack_configure request with the serial sent in this configure event at - some point before committing the new surface. - - The client is free to dismiss all but the last configure event it - received. - - The width and height arguments specify the size of the window in - surface-local coordinates. - - The size is a hint, in the sense that the client is free to ignore it if - it doesn't resize, pick a smaller size (to satisfy aspect ratio or - resize in steps of NxM pixels). If the client picks a smaller size and - is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the - surface will be centered on this axis. - - If the width or height arguments are zero, it means the client should - decide its own window dimension. - - - - - - - - - The closed event is sent by the compositor when the surface will no - longer be shown. The output may have been destroyed or the user may - have asked for it to be removed. Further changes to the surface will be - ignored. The client should destroy the resource after receiving this - event, and create a new surface if they so choose. - - - - - - - - - - - - - - - - - - - - - - - Change the layer that the surface is rendered on. - - Layer is double-buffered, see wl_surface.commit. - - - - - - - - - Requests an edge for the exclusive zone to apply. The exclusive - edge will be automatically deduced from anchor points when possible, - but when the surface is anchored to a corner, it will be necessary - to set it explicitly to disambiguate, as it is not possible to deduce - which one of the two corner edges should be used. - - The edge must be one the surface is anchored to, otherwise the - invalid_exclusive_edge protocol error will be raised. - - - - - diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 45a8ac3..0000000 --- a/src/common.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#define OPENXR_CHECK(fn_call, ...) \ - do { \ - XrResult result = fn_call(__VA_ARGS__); \ - if (result != XR_SUCCESS) { \ - std::array msg {}; \ - xrResultToString(nullptr, result, msg.data()); \ - throw std::runtime_error( \ - std::format("OpenXR call '{}' failed (code {}): {}", #fn_call, \ - static_cast(result), msg.data())); \ - } \ - } while (0) diff --git a/src/compositor.cpp b/src/compositor.cpp deleted file mode 100644 index 189f765..0000000 --- a/src/compositor.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "compositor.h" - -#include -extern "C" { -#include -#include -#include - -wlr_scene* wlr_scene_create(); -} - -#include -#include - -#include -#include -#include -#include - -void handle_new_output(struct wl_listener* l, void* d) -{ - (void)l; - (void)d; -} - -void handle_new_input(struct wl_listener* l, void* d) -{ - (void)l; - (void)d; -} - -void handle_xdg_toplevel(struct wl_listener* l, void* d) -{ - (void)l; - (void)d; -} - -void handle_xdg_popup(struct wl_listener* l, void* d) -{ - (void)l; - (void)d; -} - -Compositor::Compositor() -{ - // init logging + display + event loop - wlr_log_init(WLR_DEBUG, nullptr); - m_display = wl_display_create(); - m_event_loop = wl_display_get_event_loop(m_display); - - // openxr backend - m_backend = wlr_openxr_backend_create(m_display, m_event_loop); - if (!m_backend) - throw std::runtime_error("backend fail"); - - // renderer + allocator - m_renderer = wlr_renderer_autocreate(m_backend); - if (!m_renderer) - throw std::runtime_error("Failed to create wlr_renderer."); - wlr_renderer_init_wl_display(m_renderer, m_display); - m_allocator = wlr_allocator_autocreate(m_backend, m_renderer); - if (!m_allocator) - throw std::runtime_error("Failed to create wlr_allocator."); - - // compositor/subcompositor/data-device - m_compositor = wlr_compositor_create(m_display, 4, m_renderer); - if (!m_compositor) - throw std::runtime_error("Failed to create wlr_compositor."); - m_subcompositor = wlr_subcompositor_create(m_display); - if (!m_subcompositor) - throw std::runtime_error("Failed to create wlr_subcompositor."); - m_data_device = wlr_data_device_manager_create(m_display); - if (!m_data_device) - throw std::runtime_error("Failed to create wlr_data_device_manager."); - - // scene + output layout - m_scene = wlr_scene_create(); - if (!m_scene) - throw std::runtime_error("Failed to create wlr_scene."); - m_output_layout = wlr_output_layout_create(m_display); - if (!m_output_layout) - throw std::runtime_error("Failed to create wlr_output_layout."); - - // seat for input - m_seat = wlr_seat_create(m_display, "seat0"); - if (!m_seat) - throw std::runtime_error("Failed to create wlr_seat."); - - // xdg shell - m_xdg_shell = wlr_xdg_shell_create(m_display, 3); - if (!m_xdg_shell) - throw std::runtime_error("Failed to create wlr_xdg_shell."); - m_new_xdg_toplevel.notify = handle_xdg_toplevel; - wl_signal_add(&m_xdg_shell->events.new_toplevel, &m_new_xdg_toplevel); - m_new_xdg_popup.notify = handle_xdg_popup; - wl_signal_add(&m_xdg_shell->events.new_popup, &m_new_xdg_popup); - - // hook up backend signals - m_new_output.notify = handle_new_output; - wl_signal_add(&m_backend->events.new_output, &m_new_output); - m_new_input.notify = handle_new_input; - wl_signal_add(&m_backend->events.new_input, &m_new_input); -} - -Compositor::~Compositor() -{ - if (m_backend) { - wlr_backend_destroy(m_backend); - m_backend = nullptr; - } - if (m_display) { - wl_display_destroy(m_display); - m_display = nullptr; - } -} - -void Compositor::run() -{ - char const* socket = wl_display_add_socket_auto(m_display); - if (!socket) { - throw std::runtime_error("Failed to create socket"); - } - - if (!wlr_backend_start(m_backend)) { - throw std::runtime_error("Failed to start wlroots backend"); - } - - setenv("WAYLAND_DISPLAY", socket, true); - - wlr_log( - WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s", socket); - - wl_display_run(m_display); -} diff --git a/src/compositor.h b/src/compositor.h deleted file mode 100644 index 2847749..0000000 --- a/src/compositor.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -} -#include "wlr/openxr_gl.h" - -struct wlr_scene; - -struct Compositor { - Compositor(); - ~Compositor(); - - void run(); - void stop() { wl_display_terminate(m_display); } - - wl_listener m_new_output; - -private: - // wlroots integration - wl_display* m_display = nullptr; - wl_event_loop* m_event_loop = nullptr; - wlr_backend* m_backend = nullptr; - - wlr_renderer* m_renderer = nullptr; - wlr_allocator* m_allocator = nullptr; - wlr_compositor* m_compositor = nullptr; - wlr_subcompositor* m_subcompositor = nullptr; - wlr_data_device_manager* m_data_device = nullptr; - wlr_scene* m_scene = nullptr; - wlr_output_layout* m_output_layout = nullptr; - wlr_xdg_shell* m_xdg_shell = nullptr; - wlr_seat* m_seat = nullptr; - - wl_listener m_new_input; - wl_listener m_new_xdg_toplevel; - wl_listener m_new_xdg_popup; -}; diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 6175d44..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "compositor.h" - -#include -#include -#include - -std::unique_ptr g_c; - -int main(void) -{ - g_c = std::make_unique(); - std::signal(SIGINT, [](int) { g_c->stop(); }); - g_c->run(); - - std::println("bai bai~!"); -} diff --git a/src/wlr/backend.cpp b/src/wlr/backend.cpp deleted file mode 100644 index 3d2d486..0000000 --- a/src/wlr/backend.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "openxr_gl.h" - -extern "C" { -#include -} - -extern "C" { - -struct wlr_backend* wlr_my_backend_create( - struct wl_event_loop* loop, char const* name) -{ - (void)name; - return wlr_openxr_backend_create(nullptr, loop); -} - -bool wlr_backend_is_mybackend(struct wlr_backend* backend) -{ - return wlr_backend_is_openxr(backend); -} -} diff --git a/src/wlr/openxr_gl.cpp b/src/wlr/openxr_gl.cpp deleted file mode 100644 index 8af3070..0000000 --- a/src/wlr/openxr_gl.cpp +++ /dev/null @@ -1,359 +0,0 @@ -#include "openxr_gl.h" - -extern "C" { -#include -#include -#include -#include -} - -#include -#include - -#define GL_GLEXT_PROTOTYPES -#include -#include -#include -#include -#include -#include -#include -// Internal backend definition -struct openxr_backend { - wlr_backend base; - wl_display* display; - wl_event_loop* event_loop; - XrInstance instance {}; - XrSession session {}; - XrSpace app_space { XR_NULL_HANDLE }; - XrSwapchain swapchain { XR_NULL_HANDLE }; - int32_t width = 0, height = 0; - std::vector swapchain_images; - std::vector framebuffers; - bool started = false; - struct wlr_output* output = nullptr; -}; - -static void output_destroy(struct wlr_output* wlr_output) { (void)wlr_output; } - -static bool output_test( - struct wlr_output* wlr_output, const struct wlr_output_state* state) -{ - (void)wlr_output; - (void)state; - return true; -} - -static bool output_commit( - struct wlr_output* wlr_output, const struct wlr_output_state* state) -{ - // Retrieve our backend - auto* xr = reinterpret_cast(wlr_output->backend); - (void)state; - // Wait for frame - XrFrameState frameState { XR_TYPE_FRAME_STATE }; - xrWaitFrame(xr->session, nullptr, &frameState); - xrBeginFrame(xr->session, nullptr); - // Locate views - uint32_t viewCount = static_cast(xr->framebuffers.size()); - std::vector views(viewCount, { XR_TYPE_VIEW }); - XrViewLocateInfo viewLocInfo { XR_TYPE_VIEW_LOCATE_INFO }; - viewLocInfo.viewConfigurationType - = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO; - viewLocInfo.displayTime = frameState.predictedDisplayTime; - viewLocInfo.space = xr->app_space; - XrViewState viewState { XR_TYPE_VIEW_STATE }; - uint32_t viewCountOutput; - xrLocateViews(xr->session, &viewLocInfo, &viewState, viewCount, - &viewCountOutput, views.data()); - // Prepare projection views - std::vector projViews( - viewCountOutput, { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW }); - for (uint32_t i = 0; i < viewCountOutput; ++i) { - // Acquire swapchain image - XrSwapchainImageAcquireInfo acqInfo { - XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO - }; - uint32_t imgIndex; - xrAcquireSwapchainImage(xr->swapchain, &acqInfo, &imgIndex); - XrSwapchainImageWaitInfo waitInfo { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO }; - waitInfo.timeout = XR_INFINITE_DURATION; - xrWaitSwapchainImage(xr->swapchain, &waitInfo); - // Bind framebuffer and clear - glBindFramebuffer(GL_FRAMEBUFFER, xr->framebuffers[imgIndex]); - glViewport(0, 0, xr->width, xr->height); - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // TODO: render scene (e.g., wlr_scene_render) - // Release swapchain image - { - XrSwapchainImageReleaseInfo relInfo { - XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO - }; - xrReleaseSwapchainImage(xr->swapchain, &relInfo); - } - // Setup projection view - projViews[i].pose = views[i].pose; - projViews[i].fov = views[i].fov; - projViews[i].subImage.swapchain = xr->swapchain; - projViews[i].subImage.imageArrayIndex = imgIndex; - // Set image rectangle offset and extent - projViews[i].subImage.imageRect.offset.x = 0; - projViews[i].subImage.imageRect.offset.y = 0; - projViews[i].subImage.imageRect.extent.width = xr->width; - projViews[i].subImage.imageRect.extent.height = xr->height; - } - // Unbind - glBindFramebuffer(GL_FRAMEBUFFER, 0); - // End frame - XrCompositionLayerProjection layer { XR_TYPE_COMPOSITION_LAYER_PROJECTION }; - layer.space = xr->app_space; - layer.viewCount = static_cast(projViews.size()); - layer.views = projViews.data(); - XrCompositionLayerBaseHeader const* layers[] - = { reinterpret_cast(&layer) }; - XrFrameEndInfo frameEndInfo { XR_TYPE_FRAME_END_INFO }; - frameEndInfo.displayTime = frameState.predictedDisplayTime; - frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; - frameEndInfo.layerCount = 1; - frameEndInfo.layers = layers; - xrEndFrame(xr->session, &frameEndInfo); - return true; -} - -static const struct wlr_drm_format_set* output_get_primary_formats( - struct wlr_output* wlr_output, uint32_t buffer_caps) -{ - (void)wlr_output; - (void)buffer_caps; - return NULL; -} - -static const struct wlr_output_impl output_impl = { - .destroy = output_destroy, - .test = output_test, - .commit = output_commit, - .get_primary_formats = output_get_primary_formats, -}; - -static bool backend_start(wlr_backend* backend) -{ - auto* xr = reinterpret_cast(backend); - if (xr->started) - return true; - - XrApplicationInfo ai {}; - std::strncpy( - ai.applicationName, "LunarWM", XR_MAX_APPLICATION_NAME_SIZE - 1); - ai.applicationVersion = 1; - std::strncpy(ai.engineName, "LunarWM", XR_MAX_ENGINE_NAME_SIZE - 1); - ai.engineVersion = 1; - ai.apiVersion = XR_API_VERSION_1_0; - - char const* exts[] = { - XR_EXT_DEBUG_UTILS_EXTENSION_NAME, - XR_KHR_OPENGL_ENABLE_EXTENSION_NAME, - }; - - XrInstanceCreateInfo ic { XR_TYPE_INSTANCE_CREATE_INFO }; - ic.applicationInfo = ai; - ic.enabledExtensionCount = sizeof(exts) / sizeof(exts[0]); - ic.enabledExtensionNames = exts; - - if (xrCreateInstance(&ic, &xr->instance) != XR_SUCCESS) { - wlr_log(WLR_ERROR, "Failed to create OpenXR instance"); - return false; - } - - XrSystemGetInfo sgi { XR_TYPE_SYSTEM_GET_INFO }; - sgi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; - XrSystemId system_id; - if (xrGetSystem(xr->instance, &sgi, &system_id) != XR_SUCCESS) { - wlr_log(WLR_ERROR, "xrGetSystem failed"); - return false; - } - - PFN_xrGetOpenGLGraphicsRequirementsKHR get_reqs; - xrGetInstanceProcAddr(xr->instance, "xrGetOpenGLGraphicsRequirementsKHR", - reinterpret_cast(&get_reqs)); - XrGraphicsRequirementsOpenGLKHR gl_reqs { - XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR - }; - get_reqs(xr->instance, system_id, &gl_reqs); - - Display* dpy = XOpenDisplay(nullptr); - if (!dpy) { - wlr_log(WLR_ERROR, "Failed to open X display"); - return false; - } - int screen = DefaultScreen(dpy); - static int vis_attrs[] = { GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, - GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, - GLX_TRUE_COLOR, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, True, None }; - int fbcount; - GLXFBConfig* fbcs = glXChooseFBConfig(dpy, screen, vis_attrs, &fbcount); - if (!fbcs || !fbcount) { - wlr_log(WLR_ERROR, "No GLXFBConfig found"); - return false; - } - GLXFBConfig fbc = fbcs[0]; - XFree(fbcs); - - XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbc); - Window root = RootWindow(dpy, screen); - XSetWindowAttributes swa; - swa.colormap = XCreateColormap(dpy, root, vi->visual, AllocNone); - swa.event_mask = ExposureMask; - Window win = XCreateWindow(dpy, root, 0, 0, 16, 16, 0, vi->depth, - InputOutput, vi->visual, CWColormap | CWEventMask, &swa); - GLXContext ctx - = glXCreateNewContext(dpy, fbc, GLX_RGBA_TYPE, nullptr, True); - glXMakeContextCurrent(dpy, win, win, ctx); - - XrGraphicsBindingOpenGLXlibKHR bind { - XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR - }; - bind.xDisplay = dpy; - bind.visualid = vi->visualid; - bind.glxFBConfig = fbc; - bind.glxDrawable = win; - bind.glxContext = ctx; - - XrSessionCreateInfo sci { XR_TYPE_SESSION_CREATE_INFO }; - sci.next = &bind; - sci.systemId = system_id; - if (xrCreateSession(xr->instance, &sci, &xr->session) != XR_SUCCESS) { - wlr_log(WLR_ERROR, "xrCreateSession failed"); - return false; - } - // Create reference space - XrReferenceSpaceCreateInfo spaceInfo { - XR_TYPE_REFERENCE_SPACE_CREATE_INFO - }; - spaceInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; - spaceInfo.poseInReferenceSpace = { { 0, 0, 0, 1 }, { 0, 0, 0 } }; - if (xrCreateReferenceSpace(xr->session, &spaceInfo, &xr->app_space) - != XR_SUCCESS) { - wlr_log(WLR_ERROR, "xrCreateReferenceSpace failed"); - return false; - } - // Get recommended view configuration - uint32_t viewCount; - xrEnumerateViewConfigurationViews(xr->instance, system_id, - XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 0, &viewCount, nullptr); - std::vector viewConfigs( - viewCount, { XR_TYPE_VIEW_CONFIGURATION_VIEW }); - xrEnumerateViewConfigurationViews(xr->instance, system_id, - XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, viewCount, &viewCount, - viewConfigs.data()); - xr->width = viewConfigs[0].recommendedImageRectWidth; - xr->height = viewConfigs[0].recommendedImageRectHeight; - // Create swapchain - uint32_t formatCount; - xrEnumerateSwapchainFormats(xr->session, 0, &formatCount, nullptr); - std::vector formats(formatCount); - xrEnumerateSwapchainFormats( - xr->session, formatCount, &formatCount, formats.data()); - int64_t swapFormat = formats.empty() ? 0 : formats[0]; - XrSwapchainCreateInfo swapchain_ci { XR_TYPE_SWAPCHAIN_CREATE_INFO }; - swapchain_ci.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_ci.format = swapFormat; - swapchain_ci.sampleCount = 1; - swapchain_ci.width = xr->width; - swapchain_ci.height = xr->height; - swapchain_ci.faceCount = 1; - swapchain_ci.arraySize = viewCount; - swapchain_ci.mipCount = 1; - if (xrCreateSwapchain(xr->session, &swapchain_ci, &xr->swapchain) - != XR_SUCCESS) { - wlr_log(WLR_ERROR, "xrCreateSwapchain failed"); - return false; - } - // Enumerate swapchain images - uint32_t imageCount; - xrEnumerateSwapchainImages(xr->swapchain, 0, &imageCount, nullptr); - xr->swapchain_images.resize( - imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR }); - xrEnumerateSwapchainImages(xr->swapchain, imageCount, &imageCount, - reinterpret_cast( - xr->swapchain_images.data())); - // Create framebuffers for each image - xr->framebuffers.resize(imageCount); - for (uint32_t i = 0; i < imageCount; ++i) { - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, xr->swapchain_images[i].image, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - xr->framebuffers[i] = fbo; - } - - xr->output = static_cast(calloc(1, sizeof(wlr_output))); - if (xr->output) { - wlr_output_init( - xr->output, &xr->base, &output_impl, xr->event_loop, nullptr); - wlr_output_set_name(xr->output, "OpenXR"); - wlr_output_create_global(xr->output, xr->display); - } - - xr->started = true; - wlr_log(WLR_INFO, "OpenXR backend started"); - return true; -} - -static void backend_destroy(wlr_backend* backend) -{ - auto* xr = reinterpret_cast(backend); - // destroy swapchain and framebuffers - if (xr->swapchain) { - xrDestroySwapchain(xr->swapchain); - xr->swapchain = XR_NULL_HANDLE; - } - for (auto fbo : xr->framebuffers) { - glDeleteFramebuffers(1, &fbo); - } - // destroy reference space - if (xr->app_space) { - xrDestroySpace(xr->app_space); - xr->app_space = XR_NULL_HANDLE; - } - // destroy XR session and instance - if (xr->session) { - xrDestroySession(xr->session); - } - if (xr->instance) { - xrDestroyInstance(xr->instance); - } - free(xr); -} - -static int backend_get_drm_fd(wlr_backend* backend) -{ - (void)backend; - return -1; -} - -static wlr_backend_impl const backend_impl = { - .start = backend_start, - .destroy = backend_destroy, - .get_drm_fd = backend_get_drm_fd, -}; - -wlr_backend* wlr_openxr_backend_create(wl_display* display, wl_event_loop* loop) -{ - openxr_backend* b = static_cast(calloc(1, sizeof(*b))); - - if (!b) - return nullptr; - b->display = display; - b->event_loop = loop; - wlr_backend_init(&b->base, &backend_impl); - return &b->base; -} - -bool wlr_backend_is_openxr(wlr_backend* backend) -{ - return backend->impl == &backend_impl; -} diff --git a/src/wlr/openxr_gl.h b/src/wlr/openxr_gl.h deleted file mode 100644 index 754386a..0000000 --- a/src/wlr/openxr_gl.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -struct wlr_backend; -struct wl_display; -struct wl_event_loop; - -struct wlr_backend* wlr_openxr_backend_create( - struct wl_display* display, struct wl_event_loop* loop); - -bool wlr_backend_is_openxr(struct wlr_backend* backend); - -#ifdef __cplusplus -} -#endif diff --git a/src/wlr/output.cpp b/src/wlr/output.cpp deleted file mode 100644 index bed5a0c..0000000 --- a/src/wlr/output.cpp +++ /dev/null @@ -1,91 +0,0 @@ -extern "C" { -#include -#include -#include -} - -extern "C" { - -static void parse_setup(struct wlr_output* output) -{ - (void)output; - // TODO: parse your backend’s setup (e.g. native display info) -} - -static bool output_set_custom_mode(struct wlr_output* wlr_output, int32_t width, - int32_t height, int32_t refresh) -{ - (void)wlr_output; - (void)width; - (void)height; - (void)refresh; - // Intentionally left blank - return true; -} - -static void output_destroy(struct wlr_output* wlr_output) { (void)wlr_output; } - -static bool output_test( - struct wlr_output* wlr_output, const struct wlr_output_state* state) -{ - (void)wlr_output; - (void)state; - // TODO: check if this state is supported - return true; -} - -static bool output_commit( - struct wlr_output* wlr_output, const struct wlr_output_state* state) -{ - (void)wlr_output; - (void)state; - // TODO: apply enable/disable, mode, buffer, etc. - return true; -} - -static bool output_set_cursor(struct wlr_output* wlr_output, - struct wlr_buffer* buffer, int32_t hotspot_x, int32_t hotspot_y) -{ - (void)wlr_output; - (void)buffer; - (void)hotspot_x; - (void)hotspot_y; - // TODO: upload cursor image - return false; -} - -static bool output_move_cursor(struct wlr_output* wlr_output, int x, int y) -{ - (void)wlr_output; - (void)x; - (void)y; - // TODO: move cursor to x, y - return true; -} - -static const struct wlr_drm_format_set* output_get_primary_formats( - struct wlr_output* wlr_output, uint32_t buffer_caps) -{ - (void)wlr_output; - (void)buffer_caps; - // TODO: return DRM/SHM formats your backend supports - return NULL; -} - -static const struct wlr_output_impl output_impl = { - .set_cursor = output_set_cursor, - .move_cursor = output_move_cursor, - .destroy = output_destroy, - .test = output_test, - .commit = output_commit, - .get_primary_formats = output_get_primary_formats, -}; - -struct wlr_output* wlr_my_output_create(struct wlr_backend* backend) -{ - (void)backend; - // TODO: alloc + init your output struct and call - // wlr_output_init(&output->base, backend, &output_impl, …) - return NULL; -} -} diff --git a/tools/clang-format.sh b/tools/clang-format.sh deleted file mode 100755 index 33e87d3..0000000 --- a/tools/clang-format.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -cd $(dirname $0)/.. || exit 1 -find src '(' -name '*.c' -o -name '*.h' -o -name '*.cpp' -o -name '*.hpp' ')' -print0 | xargs -0 clang-format -i - -echo 'Formatted source files in src/' \ No newline at end of file diff --git a/tools/tokei.sh b/tools/tokei.sh deleted file mode 100755 index e845393..0000000 --- a/tools/tokei.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -cd $(dirname $0)/.. || exit 1 -tokei src - -exit 0 \ No newline at end of file diff --git a/wlroots b/wlroots deleted file mode 160000 index 8c7041c..0000000 --- a/wlroots +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8c7041c4e842c9fb029a6371eb53f73aa98e7b31