28
.clang-format
Normal file
28
.clang-format
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
UseTab: ForIndentation
|
||||
TabWidth: 4
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 80
|
||||
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
BasedOnStyle: WebKit
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentRequiresClause: false
|
||||
InsertNewlineAtEOF: true
|
||||
LineEnding: LF
|
||||
NamespaceIndentation: None
|
||||
QualifierAlignment: Right
|
||||
RemoveSemicolon: true
|
||||
RequiresClausePosition: WithFollowing
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SpaceAfterTemplateKeyword: false
|
||||
|
||||
...
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.cache
|
||||
[Bb]uild*
|
||||
|
||||
54
CMakeLists.txt
Normal file
54
CMakeLists.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(lunarwm VERSION 0.0.1 LANGUAGES C CXX)
|
||||
|
||||
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}
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
src/wlr/backend.cpp
|
||||
src/wlr/output.cpp
|
||||
|
||||
src/compositor.cpp
|
||||
src/main.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
OpenGL::GL
|
||||
openxr_loader
|
||||
${wayland_LIBRARIES}
|
||||
${X11_LIBRARIES}
|
||||
${GLM_LIBRARIES}
|
||||
${Wlroots_LIBRARIES}
|
||||
)
|
||||
10
cmake/FindWlroots.cmake
Normal file
10
cmake/FindWlroots.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
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)
|
||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1751011381,
|
||||
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
65
flake.nix
Normal file
65
flake.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
description = "LunarWM is a VR-based Wayland compositor";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
system = system;
|
||||
config.cudaSupport = true;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
pkg-config
|
||||
cmake
|
||||
ninja
|
||||
clang-tools
|
||||
lldb
|
||||
|
||||
# For wlroots
|
||||
libxkbcommon
|
||||
libdrm
|
||||
xorg.libxcb
|
||||
pixman
|
||||
libgbm
|
||||
vulkan-loader
|
||||
lcms2
|
||||
seatd
|
||||
libdisplay-info
|
||||
libliftoff
|
||||
libinput
|
||||
xorg.xcbutilrenderutil
|
||||
xorg.xcbutilwm
|
||||
xorg.xcbutilerrors
|
||||
|
||||
wlroots
|
||||
libffi
|
||||
wayland
|
||||
wayland-scanner
|
||||
wayland-protocols
|
||||
|
||||
openxr-loader
|
||||
libGL
|
||||
glm
|
||||
xorg.libX11
|
||||
xorg.libXau
|
||||
xorg.libXdmcp
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
15
src/common.h
Normal file
15
src/common.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <format>
|
||||
|
||||
#define OPENXR_CHECK(fn_call, ...) \
|
||||
do { \
|
||||
XrResult result = fn_call(__VA_ARGS__); \
|
||||
if (result != XR_SUCCESS) { \
|
||||
std::array<char, XR_MAX_RESULT_STRING_SIZE> msg {}; \
|
||||
xrResultToString(nullptr, result, msg.data()); \
|
||||
throw std::runtime_error( \
|
||||
std::format("OpenXR call '{}' failed (code {}): {}", #fn_call, \
|
||||
static_cast<int>(result), msg.data())); \
|
||||
} \
|
||||
} while (0)
|
||||
259
src/compositor.cpp
Normal file
259
src/compositor.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include "compositor.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
#include <vector>
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
void Compositor::create_instance()
|
||||
{
|
||||
// Wow, can't believe this compositor uses AI!
|
||||
XrApplicationInfo ai {
|
||||
.applicationName = {},
|
||||
.applicationVersion = 1,
|
||||
.engineName = {},
|
||||
.engineVersion = 1,
|
||||
.apiVersion = XR_API_VERSION_1_0,
|
||||
};
|
||||
|
||||
std::strncpy(
|
||||
ai.applicationName, "LunarWM", XR_MAX_APPLICATION_NAME_SIZE - 1);
|
||||
std::strncpy(ai.engineName, "LunarWM Engine", XR_MAX_ENGINE_NAME_SIZE - 1);
|
||||
|
||||
std::vector<char const*> const instance_extensions {
|
||||
XR_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
||||
XR_KHR_OPENGL_ENABLE_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
std::vector<XrExtensionProperties> extension_props;
|
||||
{ // Populate extension_props
|
||||
uint32_t len = 0;
|
||||
OPENXR_CHECK(
|
||||
xrEnumerateInstanceExtensionProperties, nullptr, 0, &len, nullptr);
|
||||
extension_props.resize(len, { XR_TYPE_EXTENSION_PROPERTIES });
|
||||
OPENXR_CHECK(xrEnumerateInstanceExtensionProperties, nullptr, len, &len,
|
||||
extension_props.data());
|
||||
}
|
||||
|
||||
// Check that we have all our requested extensions available
|
||||
for (auto const& requested_instance_extension : instance_extensions) {
|
||||
bool found = false;
|
||||
|
||||
for (auto const& eprop : extension_props) {
|
||||
if (strcmp(requested_instance_extension, eprop.extensionName)
|
||||
== 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw std::runtime_error(std::format(
|
||||
"Failed to find extension: {}", requested_instance_extension));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Create our instance
|
||||
XrInstanceCreateInfo ci {
|
||||
.type = XR_TYPE_INSTANCE_CREATE_INFO,
|
||||
.next = nullptr,
|
||||
.createFlags = 0,
|
||||
.applicationInfo = ai,
|
||||
.enabledApiLayerCount = 0,
|
||||
.enabledApiLayerNames = nullptr,
|
||||
.enabledExtensionCount
|
||||
= static_cast<uint32_t>(instance_extensions.size()),
|
||||
.enabledExtensionNames = instance_extensions.data(),
|
||||
};
|
||||
|
||||
OPENXR_CHECK(xrCreateInstance, &ci, &m_xr_instance);
|
||||
}
|
||||
}
|
||||
|
||||
void Compositor::destroy_instance()
|
||||
{
|
||||
OPENXR_CHECK(xrDestroyInstance, m_xr_instance);
|
||||
}
|
||||
|
||||
void Compositor::create_session()
|
||||
{
|
||||
XrSystemId system_id;
|
||||
|
||||
{ // Get system ID.
|
||||
XrSystemGetInfo system_gi { XR_TYPE_SYSTEM_GET_INFO };
|
||||
system_gi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
OPENXR_CHECK(xrGetSystem, m_xr_instance, &system_gi, &system_id);
|
||||
|
||||
// NOTE: Might be useful later.
|
||||
XrSystemProperties system_properties = { XR_TYPE_SYSTEM_PROPERTIES };
|
||||
OPENXR_CHECK(xrGetSystemProperties, m_xr_instance, system_id,
|
||||
&system_properties);
|
||||
}
|
||||
|
||||
{ // Get GLX graphics requirements
|
||||
PFN_xrGetOpenGLGraphicsRequirementsKHR xr_get_gl_req = nullptr;
|
||||
xrGetInstanceProcAddr(m_xr_instance,
|
||||
"xrGetOpenGLGraphicsRequirementsKHR",
|
||||
reinterpret_cast<PFN_xrVoidFunction*>(&xr_get_gl_req));
|
||||
|
||||
XrGraphicsRequirementsOpenGLKHR gl_req {
|
||||
XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR
|
||||
};
|
||||
OPENXR_CHECK(xr_get_gl_req, m_xr_instance, system_id, &gl_req);
|
||||
|
||||
std::println("OpenGL requirements: min=0x{:X}, max=0x{:X}",
|
||||
gl_req.minApiVersionSupported, gl_req.maxApiVersionSupported);
|
||||
}
|
||||
|
||||
XrGraphicsBindingOpenGLXlibKHR graphics_binding {};
|
||||
|
||||
{ // Xlib stuff
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
if (!display)
|
||||
throw std::runtime_error("Failed to open X display");
|
||||
|
||||
int screen = DefaultScreen(display);
|
||||
|
||||
static int visual_attribs[] = {
|
||||
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* fbc
|
||||
= glXChooseFBConfig(display, screen, visual_attribs, &fbcount);
|
||||
if (!fbc)
|
||||
throw std::runtime_error("No GLXFBConfig found");
|
||||
|
||||
// just grab first config
|
||||
GLXFBConfig best_fbc = fbc[0];
|
||||
XFree(fbc);
|
||||
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(display, best_fbc);
|
||||
if (!vi)
|
||||
throw std::runtime_error("Failed to get XVisualInfo");
|
||||
|
||||
Window root = RootWindow(display, screen);
|
||||
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = XCreateColormap(display, root, vi->visual, AllocNone);
|
||||
swa.event_mask = ExposureMask | KeyPressMask;
|
||||
|
||||
Window win = XCreateWindow(display, root, 0, 0, 800, 600, 0, vi->depth,
|
||||
InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
|
||||
XMapWindow(display, win);
|
||||
XStoreName(display, win, "LunarWM OpenXR");
|
||||
|
||||
GLXContext glc = glXCreateNewContext(
|
||||
display, best_fbc, GLX_RGBA_TYPE, nullptr, True);
|
||||
if (!glc)
|
||||
throw std::runtime_error("Failed to create GLX context");
|
||||
|
||||
if (!glXMakeContextCurrent(display, win, win, glc))
|
||||
throw std::runtime_error("glXMakeContextCurrent failed");
|
||||
|
||||
// fill in OpenXR graphics binding
|
||||
graphics_binding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
|
||||
graphics_binding.next = nullptr;
|
||||
graphics_binding.xDisplay = display;
|
||||
graphics_binding.visualid = vi->visualid;
|
||||
graphics_binding.glxFBConfig = best_fbc;
|
||||
graphics_binding.glxDrawable = win;
|
||||
graphics_binding.glxContext = glc;
|
||||
}
|
||||
|
||||
{ // Create session
|
||||
XrSessionCreateInfo ci { XR_TYPE_SESSION_CREATE_INFO };
|
||||
ci.next = &graphics_binding;
|
||||
ci.systemId = system_id;
|
||||
ci.createFlags = 0;
|
||||
OPENXR_CHECK(xrCreateSession, m_xr_instance, &ci, &m_session);
|
||||
}
|
||||
}
|
||||
|
||||
void Compositor::destroy_session()
|
||||
{
|
||||
OPENXR_CHECK(xrDestroySession, m_session);
|
||||
}
|
||||
|
||||
void Compositor::poll_events()
|
||||
{
|
||||
XrEventDataBuffer event_data { XR_TYPE_EVENT_DATA_BUFFER };
|
||||
auto xr_poll_events = [&]() -> bool {
|
||||
event_data = { XR_TYPE_EVENT_DATA_BUFFER };
|
||||
return xrPollEvent(m_xr_instance, &event_data) == XR_SUCCESS;
|
||||
};
|
||||
|
||||
while (xr_poll_events()) {
|
||||
switch (event_data.type) {
|
||||
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
|
||||
XrEventDataSessionStateChanged* session_state_changed
|
||||
= reinterpret_cast<XrEventDataSessionStateChanged*>(
|
||||
&event_data);
|
||||
if (session_state_changed->session != m_session) {
|
||||
std::println(std::cerr,
|
||||
"XrEventDataSessionStateChanged for unknown Session");
|
||||
break;
|
||||
}
|
||||
if (session_state_changed->state == XR_SESSION_STATE_READY) {
|
||||
XrSessionBeginInfo session_begin_info {
|
||||
XR_TYPE_SESSION_BEGIN_INFO
|
||||
};
|
||||
session_begin_info.primaryViewConfigurationType
|
||||
= XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
||||
OPENXR_CHECK(xrBeginSession, m_session, &session_begin_info);
|
||||
m_session_running = true;
|
||||
}
|
||||
if (session_state_changed->state == XR_SESSION_STATE_STOPPING) {
|
||||
OPENXR_CHECK(xrEndSession, m_session);
|
||||
m_session_running = false;
|
||||
}
|
||||
if (session_state_changed->state == XR_SESSION_STATE_EXITING
|
||||
|| session_state_changed->state
|
||||
== XR_SESSION_STATE_LOSS_PENDING) {
|
||||
m_session_running = false;
|
||||
m_running = false;
|
||||
}
|
||||
m_session_state = session_state_changed->state;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Compositor::run()
|
||||
{
|
||||
while (m_running) {
|
||||
this->poll_events();
|
||||
|
||||
if (m_session_running) {
|
||||
// TODO: Render frame
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/compositor.h
Normal file
37
src/compositor.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
struct Compositor {
|
||||
Compositor()
|
||||
{
|
||||
this->create_instance();
|
||||
this->create_session();
|
||||
}
|
||||
|
||||
~Compositor()
|
||||
{
|
||||
this->destroy_session();
|
||||
this->destroy_instance();
|
||||
}
|
||||
|
||||
void run();
|
||||
void stop() { m_running = false; }
|
||||
|
||||
private:
|
||||
void create_instance();
|
||||
void destroy_instance();
|
||||
|
||||
void create_session();
|
||||
void destroy_session();
|
||||
|
||||
void poll_events();
|
||||
|
||||
bool m_running = true;
|
||||
|
||||
// OpenXR related stuff
|
||||
XrInstance m_xr_instance;
|
||||
bool m_session_running = false;
|
||||
XrSession m_session = {};
|
||||
XrSessionState m_session_state = XR_SESSION_STATE_UNKNOWN;
|
||||
};
|
||||
16
src/main.cpp
Normal file
16
src/main.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "compositor.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <memory>
|
||||
#include <print>
|
||||
|
||||
std::unique_ptr<Compositor> g_c;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
g_c = std::make_unique<Compositor>();
|
||||
std::signal(SIGINT, [](int) { g_c->stop(); });
|
||||
g_c->run();
|
||||
|
||||
std::println("bai bai~!");
|
||||
}
|
||||
60
src/wlr/backend.cpp
Normal file
60
src/wlr/backend.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" {
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/util/log.h>
|
||||
}
|
||||
|
||||
struct my_backend {
|
||||
struct wlr_backend base;
|
||||
// TODO: any backend‐specific fields
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
static bool backend_start(struct wlr_backend* backend)
|
||||
{
|
||||
(void)backend;
|
||||
// TODO: start event loops, create outputs, inputs, etc.
|
||||
return true;
|
||||
}
|
||||
|
||||
static void backend_destroy(struct wlr_backend* backend)
|
||||
{
|
||||
(void)backend;
|
||||
// TODO: destroy outputs, free everything
|
||||
}
|
||||
|
||||
static int backend_get_drm_fd(struct wlr_backend* backend)
|
||||
{
|
||||
(void)backend;
|
||||
// TODO: return drm FD or -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
};
|
||||
|
||||
struct wlr_backend* wlr_my_backend_create(
|
||||
struct wl_event_loop* loop, char const* name)
|
||||
{
|
||||
(void)loop;
|
||||
(void)name;
|
||||
struct my_backend* b = (struct my_backend*)calloc(1, sizeof(*b));
|
||||
if (!b) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_backend_init(&b->base, &backend_impl);
|
||||
// TODO: store loop/name, setup
|
||||
return &b->base;
|
||||
}
|
||||
|
||||
bool wlr_backend_is_mybackend(struct wlr_backend* backend)
|
||||
{
|
||||
return backend->impl == &backend_impl;
|
||||
}
|
||||
}
|
||||
91
src/wlr/output.cpp
Normal file
91
src/wlr/output.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
extern "C" {
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user