mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 12:49:47 +01:00
Wayland: Initial progress
This commit is contained in:
parent
6ccfdd74df
commit
01766c0956
13 changed files with 864 additions and 12 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -34,3 +34,6 @@
|
||||||
build/
|
build/
|
||||||
.vscode/
|
.vscode/
|
||||||
.cache/
|
.cache/
|
||||||
|
|
||||||
|
protocols/*.cpp
|
||||||
|
protocols/*.hpp
|
|
@ -16,7 +16,7 @@ set(INCLUDE ${CMAKE_INSTALL_FULL_INCLUDEDIR})
|
||||||
set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR})
|
set(LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR})
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols hyprutils>=0.1.2)
|
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols hyprutils>=0.1.2 pixman-1 wayland-client)
|
||||||
|
|
||||||
configure_file(aquamarine.pc.in aquamarine.pc @ONLY)
|
configure_file(aquamarine.pc.in aquamarine.pc @ONLY)
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ file(GLOB_RECURSE PUBLIC_HEADERS CONFIGURE_DEPENDS "include/*.hpp")
|
||||||
add_library(aquamarine SHARED ${SRCFILES})
|
add_library(aquamarine SHARED ${SRCFILES})
|
||||||
target_include_directories( aquamarine
|
target_include_directories( aquamarine
|
||||||
PUBLIC "./include"
|
PUBLIC "./include"
|
||||||
PRIVATE "./src"
|
PRIVATE "./src" "./src/include" "./protocols"
|
||||||
)
|
)
|
||||||
set_target_properties(aquamarine PROPERTIES
|
set_target_properties(aquamarine PROPERTIES
|
||||||
VERSION ${AQUAMARINE_VERSION}
|
VERSION ${AQUAMARINE_VERSION}
|
||||||
|
@ -44,6 +44,48 @@ set_target_properties(aquamarine PROPERTIES
|
||||||
)
|
)
|
||||||
target_link_libraries(aquamarine PkgConfig::deps)
|
target_link_libraries(aquamarine PkgConfig::deps)
|
||||||
|
|
||||||
|
# Protocols
|
||||||
|
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||||
|
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||||
|
pkg_get_variable(WAYLAND_CLIENT_DIR wayland-client pkgdatadir)
|
||||||
|
message(STATUS "Found wayland-client at ${WAYLAND_CLIENT_DIR}")
|
||||||
|
|
||||||
|
function(protocolNew protoPath protoName external)
|
||||||
|
if (external)
|
||||||
|
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
|
||||||
|
else()
|
||||||
|
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||||
|
endif()
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
|
||||||
|
COMMAND hyprwayland-scanner --client ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
target_sources(aquamarine PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp)
|
||||||
|
endfunction()
|
||||||
|
function(protocolWayland)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||||
|
COMMAND hyprwayland-scanner --wayland-enums --client ${WAYLAND_CLIENT_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
target_sources(aquamarine PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
protocolWayland()
|
||||||
|
|
||||||
|
protocolNew("stable/xdg-shell" "xdg-shell" false)
|
||||||
|
|
||||||
|
# tests
|
||||||
|
add_custom_target(tests)
|
||||||
|
|
||||||
|
add_executable(simpleWindow "tests/SimpleWindow.cpp")
|
||||||
|
target_link_libraries(simpleWindow PRIVATE aquamarine PkgConfig::deps)
|
||||||
|
add_test(NAME "simpleWindow" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND simpleWindow "simpleWindow")
|
||||||
|
add_dependencies(tests simpleWindow)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
install(TARGETS aquamarine)
|
install(TARGETS aquamarine)
|
||||||
install(DIRECTORY "include/aquamarine" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
install(DIRECTORY "include/aquamarine" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <hyprutils/memory/SharedPtr.hpp>
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/signal/Signal.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
namespace Aquamarine {
|
namespace Aquamarine {
|
||||||
enum eBackendType {
|
enum eBackendType {
|
||||||
|
@ -47,8 +50,13 @@ namespace Aquamarine {
|
||||||
|
|
||||||
class IBackendImplementation {
|
class IBackendImplementation {
|
||||||
public:
|
public:
|
||||||
virtual ~IBackendImplementation();
|
virtual ~IBackendImplementation() {
|
||||||
|
;
|
||||||
|
}
|
||||||
virtual eBackendType type() = 0;
|
virtual eBackendType type() = 0;
|
||||||
|
virtual bool start() = 0;
|
||||||
|
virtual int pollFD() = 0;
|
||||||
|
virtual bool dispatchEvents() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CBackend {
|
class CBackend {
|
||||||
|
@ -63,10 +71,33 @@ namespace Aquamarine {
|
||||||
|
|
||||||
void log(eBackendLogLevel level, const std::string& msg);
|
void log(eBackendLogLevel level, const std::string& msg);
|
||||||
|
|
||||||
|
/* Enters the event loop synchronously. For simple clients, this is probably what you want. For more complex ones,
|
||||||
|
see async methods further below */
|
||||||
|
void enterLoop();
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Hyprutils::Signal::CSignal newOutput;
|
||||||
|
Hyprutils::Signal::CSignal newPointer;
|
||||||
|
Hyprutils::Signal::CSignal newKeyboard;
|
||||||
|
Hyprutils::Signal::CSignal newTouch;
|
||||||
|
} events;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CBackend();
|
CBackend();
|
||||||
|
|
||||||
std::vector<IBackendImplementation> implementations;
|
bool terminate = false;
|
||||||
|
|
||||||
|
std::vector<SBackendImplementationOptions> implementationOptions;
|
||||||
|
std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>> implementations;
|
||||||
SBackendOptions options;
|
SBackendOptions options;
|
||||||
|
|
||||||
|
//
|
||||||
|
struct {
|
||||||
|
std::condition_variable loopSignal;
|
||||||
|
std::mutex loopMutex;
|
||||||
|
std::atomic<bool> shouldProcess = false;
|
||||||
|
std::mutex loopRequestMutex;
|
||||||
|
std::mutex eventLock;
|
||||||
|
} m_sEventLoopInternals;
|
||||||
};
|
};
|
||||||
};
|
};
|
106
include/aquamarine/backend/Wayland.hpp
Normal file
106
include/aquamarine/backend/Wayland.hpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./Backend.hpp"
|
||||||
|
#include "../output/Output.hpp"
|
||||||
|
#include "../input/Input.hpp"
|
||||||
|
#include <hyprutils/memory/WeakPtr.hpp>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
|
||||||
|
namespace Aquamarine {
|
||||||
|
class CBackend;
|
||||||
|
class CWaylandBackend;
|
||||||
|
|
||||||
|
class CWaylandOutput : public IOutput {
|
||||||
|
public:
|
||||||
|
virtual ~CWaylandOutput();
|
||||||
|
virtual void commit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CWaylandOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_);
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Hyprutils::Memory::CSharedPointer<CWlSurface> surface;
|
||||||
|
Hyprutils::Memory::CSharedPointer<CXdgSurface> xdgSurface;
|
||||||
|
Hyprutils::Memory::CSharedPointer<CXdgToplevel> xdgToplevel;
|
||||||
|
} waylandState;
|
||||||
|
|
||||||
|
friend class CWaylandBackend;
|
||||||
|
friend class CWaylandPointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWaylandKeyboard : public IKeyboard {
|
||||||
|
public:
|
||||||
|
CWaylandKeyboard(Hyprutils::Memory::CSharedPointer<CWlKeyboard> keyboard_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_);
|
||||||
|
virtual ~CWaylandKeyboard();
|
||||||
|
|
||||||
|
virtual const std::string& getName();
|
||||||
|
|
||||||
|
Hyprutils::Memory::CSharedPointer<CWlKeyboard> keyboard;
|
||||||
|
Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string name = "wl_keyboard";
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWaylandPointer : public IPointer {
|
||||||
|
public:
|
||||||
|
CWaylandPointer(Hyprutils::Memory::CSharedPointer<CWlPointer> pointer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_);
|
||||||
|
virtual ~CWaylandPointer();
|
||||||
|
|
||||||
|
virtual const std::string& getName();
|
||||||
|
|
||||||
|
Hyprutils::Memory::CSharedPointer<CWlPointer> pointer;
|
||||||
|
Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string name = "wl_pointer";
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWaylandBackend : public IBackendImplementation {
|
||||||
|
public:
|
||||||
|
virtual ~CWaylandBackend();
|
||||||
|
virtual eBackendType type();
|
||||||
|
virtual bool start();
|
||||||
|
virtual int pollFD();
|
||||||
|
virtual bool dispatchEvents();
|
||||||
|
|
||||||
|
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CWaylandBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
||||||
|
|
||||||
|
void initSeat();
|
||||||
|
void initShell();
|
||||||
|
void createOutput(const std::string& szName);
|
||||||
|
|
||||||
|
//
|
||||||
|
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
||||||
|
std::vector<Hyprutils::Memory::CSharedPointer<CWaylandOutput>> outputs;
|
||||||
|
std::vector<Hyprutils::Memory::CSharedPointer<CWaylandKeyboard>> keyboards;
|
||||||
|
std::vector<Hyprutils::Memory::CSharedPointer<CWaylandPointer>> pointers;
|
||||||
|
|
||||||
|
// pointer focus
|
||||||
|
Hyprutils::Memory::CWeakPointer<CWaylandOutput> focusedOutput;
|
||||||
|
uint32_t lastEnterSerial = 0;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
wl_display* display = nullptr;
|
||||||
|
|
||||||
|
// hw-s types
|
||||||
|
Hyprutils::Memory::CSharedPointer<CWlRegistry> registry;
|
||||||
|
Hyprutils::Memory::CSharedPointer<CWlSeat> seat;
|
||||||
|
Hyprutils::Memory::CSharedPointer<CXdgWmBase> xdg;
|
||||||
|
Hyprutils::Memory::CSharedPointer<CWlCompositor> compositor;
|
||||||
|
} waylandState;
|
||||||
|
|
||||||
|
friend class CBackend;
|
||||||
|
friend class CWaylandKeyboard;
|
||||||
|
friend class CWaylandPointer;
|
||||||
|
friend class CWaylandOutput;
|
||||||
|
};
|
||||||
|
};
|
72
include/aquamarine/buffer/Buffer.hpp
Normal file
72
include/aquamarine/buffer/Buffer.hpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <tuple>
|
||||||
|
#include <hyprutils/signal/Signal.hpp>
|
||||||
|
#include <hyprutils/math/Region.hpp>
|
||||||
|
|
||||||
|
namespace Aquamarine {
|
||||||
|
enum eBufferCapability {
|
||||||
|
BUFFER_CAPABILITY_DATAPTR = (1 << 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eBufferType {
|
||||||
|
BUFFER_TYPE_DMABUF = 0,
|
||||||
|
BUFFER_TYPE_SHM,
|
||||||
|
BUFFER_TYPE_MISC,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CWLBufferResource;
|
||||||
|
|
||||||
|
struct SDMABUFAttrs {
|
||||||
|
bool success = false;
|
||||||
|
Hyprutils::Math::Vector2D size;
|
||||||
|
uint32_t format = 0; // fourcc
|
||||||
|
uint64_t modifier = 0;
|
||||||
|
|
||||||
|
int planes = 1;
|
||||||
|
std::array<uint32_t, 4> offsets = {0};
|
||||||
|
std::array<uint32_t, 4> strides = {0};
|
||||||
|
std::array<int, 4> fds = {-1, -1, -1, -1};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SSHMAttrs {
|
||||||
|
bool success = false;
|
||||||
|
int fd = 0;
|
||||||
|
uint32_t format = 0;
|
||||||
|
Hyprutils::Math::Vector2D size;
|
||||||
|
int stride = 0;
|
||||||
|
int64_t offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IBuffer {
|
||||||
|
public:
|
||||||
|
virtual ~IBuffer() {
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual eBufferCapability caps() = 0;
|
||||||
|
virtual eBufferType type() = 0;
|
||||||
|
virtual void update(const Hyprutils::Math::CRegion& damage) = 0;
|
||||||
|
virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu
|
||||||
|
virtual SDMABUFAttrs dmabuf();
|
||||||
|
virtual SSHMAttrs shm();
|
||||||
|
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
|
||||||
|
virtual void endDataPtr();
|
||||||
|
virtual void sendRelease();
|
||||||
|
virtual void lock();
|
||||||
|
virtual void unlock();
|
||||||
|
virtual bool locked();
|
||||||
|
|
||||||
|
Hyprutils::Math::Vector2D size;
|
||||||
|
bool opaque = false;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Hyprutils::Signal::CSignal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int locks = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
|
@ -1,13 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <hyprutils/signal/Signal.hpp>
|
#include <hyprutils/signal/Signal.hpp>
|
||||||
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
|
|
||||||
struct libinput_device;
|
struct libinput_device;
|
||||||
|
|
||||||
namespace Aquamarine {
|
namespace Aquamarine {
|
||||||
class IKeyboard {
|
class IKeyboard {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IKeyboard() {
|
||||||
|
events.destroy.emit();
|
||||||
|
}
|
||||||
virtual libinput_device* getLibinputHandle();
|
virtual libinput_device* getLibinputHandle();
|
||||||
|
virtual const std::string& getName() = 0;
|
||||||
|
|
||||||
|
struct SKeyEvent {
|
||||||
|
uint32_t timeMs = 0;
|
||||||
|
uint32_t key = 0;
|
||||||
|
bool pressed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SModifiersEvent {
|
||||||
|
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Hyprutils::Signal::CSignal destroy;
|
Hyprutils::Signal::CSignal destroy;
|
||||||
|
@ -18,7 +33,37 @@ namespace Aquamarine {
|
||||||
|
|
||||||
class IPointer {
|
class IPointer {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IPointer() {
|
||||||
|
events.destroy.emit();
|
||||||
|
}
|
||||||
|
|
||||||
virtual libinput_device* getLibinputHandle();
|
virtual libinput_device* getLibinputHandle();
|
||||||
|
virtual const std::string& getName() = 0;
|
||||||
|
|
||||||
|
enum ePointerAxis {
|
||||||
|
AQ_POINTER_AXIS_VERTICAL = 0,
|
||||||
|
AQ_POINTER_AXIS_HORIZONTAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SMoveEvent {
|
||||||
|
Hyprutils::Math::Vector2D delta;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SWarpEvent {
|
||||||
|
Hyprutils::Math::Vector2D absolute;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SButtonEvent {
|
||||||
|
uint32_t timeMs = 0;
|
||||||
|
uint32_t button = 0;
|
||||||
|
bool pressed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SAxisEvent {
|
||||||
|
uint32_t timeMs = 0;
|
||||||
|
ePointerAxis axis = AQ_POINTER_AXIS_VERTICAL;
|
||||||
|
double value = 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Hyprutils::Signal::CSignal destroy;
|
Hyprutils::Signal::CSignal destroy;
|
||||||
|
@ -26,6 +71,7 @@ namespace Aquamarine {
|
||||||
Hyprutils::Signal::CSignal warp;
|
Hyprutils::Signal::CSignal warp;
|
||||||
Hyprutils::Signal::CSignal button;
|
Hyprutils::Signal::CSignal button;
|
||||||
Hyprutils::Signal::CSignal axis;
|
Hyprutils::Signal::CSignal axis;
|
||||||
|
Hyprutils::Signal::CSignal frame;
|
||||||
} events;
|
} events;
|
||||||
};
|
};
|
||||||
}
|
}
|
66
include/aquamarine/output/Output.hpp
Normal file
66
include/aquamarine/output/Output.hpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <hyprutils/signal/Signal.hpp>
|
||||||
|
#include <hyprutils/memory/SharedPtr.hpp>
|
||||||
|
#include <hyprutils/math/Region.hpp>
|
||||||
|
|
||||||
|
namespace Aquamarine {
|
||||||
|
struct SOutputMode {
|
||||||
|
Hyprutils::Math::Vector2D pixelSize;
|
||||||
|
unsigned int refreshRate = 0 /* in mHz */;
|
||||||
|
bool preferred = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eOutputPresentationMode {
|
||||||
|
AQ_OUTPUT_PRESENTATION_VSYNC = 0,
|
||||||
|
AQ_OUTPUT_PRESENTATION_IMMEDIATE, // likely tearing
|
||||||
|
};
|
||||||
|
|
||||||
|
class IOutput;
|
||||||
|
|
||||||
|
class COutputState {
|
||||||
|
public:
|
||||||
|
COutputState(Hyprutils::Memory::CSharedPointer<IOutput> parent);
|
||||||
|
|
||||||
|
Hyprutils::Math::CRegion damage;
|
||||||
|
bool enabled = false;
|
||||||
|
bool adaptiveSync = false;
|
||||||
|
eOutputPresentationMode presentationMode = AQ_OUTPUT_PRESENTATION_VSYNC;
|
||||||
|
std::vector<uint16_t> gammaLut;
|
||||||
|
Hyprutils::Math::Vector2D lastModeSize;
|
||||||
|
Hyprutils::Memory::CWeakPointer<SOutputMode> mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IOutput {
|
||||||
|
public:
|
||||||
|
virtual ~IOutput() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void commit() = 0;
|
||||||
|
|
||||||
|
std::string name, description, make, model, serial;
|
||||||
|
Hyprutils::Math::Vector2D physicalSize;
|
||||||
|
bool enabled = false;
|
||||||
|
bool adaptiveSync = false;
|
||||||
|
bool nonDesktop = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
std::vector<Hyprutils::Memory::CSharedPointer<SOutputMode>> modes;
|
||||||
|
Hyprutils::Memory::CSharedPointer<COutputState> state;
|
||||||
|
|
||||||
|
//
|
||||||
|
struct SStateEvent {
|
||||||
|
Hyprutils::Math::Vector2D size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Hyprutils::Signal::CSignal destroy;
|
||||||
|
Hyprutils::Signal::CSignal frame;
|
||||||
|
Hyprutils::Signal::CSignal needsFrame;
|
||||||
|
Hyprutils::Signal::CSignal present;
|
||||||
|
Hyprutils::Signal::CSignal state;
|
||||||
|
} events;
|
||||||
|
};
|
||||||
|
}
|
0
protocols/.gitkeep
Normal file
0
protocols/.gitkeep
Normal file
|
@ -1,29 +1,92 @@
|
||||||
#include <aquamarine/backend/Backend.hpp>
|
#include <aquamarine/backend/Backend.hpp>
|
||||||
|
#include <aquamarine/backend/Wayland.hpp>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
using namespace Hyprutils::Memory;
|
using namespace Hyprutils::Memory;
|
||||||
using namespace Aquamarine;
|
using namespace Aquamarine;
|
||||||
#define SP CSharedPointer
|
#define SP CSharedPointer
|
||||||
|
|
||||||
|
static const char* backendTypeToName(eBackendType type) {
|
||||||
|
switch (type) {
|
||||||
|
case AQ_BACKEND_DRM: return "drm";
|
||||||
|
case AQ_BACKEND_HEADLESS: return "headless";
|
||||||
|
case AQ_BACKEND_WAYLAND: return "wayland";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return "invalid";
|
||||||
|
}
|
||||||
|
|
||||||
Aquamarine::CBackend::CBackend() {
|
Aquamarine::CBackend::CBackend() {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Aquamarine::SBackendImplementationOptions::SBackendImplementationOptions() {
|
||||||
|
backendType = AQ_BACKEND_WAYLAND;
|
||||||
|
backendRequestMode = AQ_BACKEND_REQUEST_IF_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::SBackendOptions::SBackendOptions() {
|
||||||
|
logFunction = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const std::vector<SBackendImplementationOptions>& backends, const SBackendOptions& options) {
|
Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const std::vector<SBackendImplementationOptions>& backends, const SBackendOptions& options) {
|
||||||
auto backend = SP<CBackend>(new CBackend());
|
auto backend = SP<CBackend>(new CBackend());
|
||||||
|
|
||||||
backend->options = options;
|
backend->options = options;
|
||||||
|
backend->implementationOptions = backends;
|
||||||
|
|
||||||
backend->log(AQ_LOG_DEBUG, "Hello world!\n");
|
backend->log(AQ_LOG_DEBUG, "Creating an Aquamarine backend!");
|
||||||
|
|
||||||
|
for (auto& b : backends) {
|
||||||
|
if (b.backendType == AQ_BACKEND_WAYLAND) {
|
||||||
|
auto ref = SP<CWaylandBackend>(new CWaylandBackend(backend));
|
||||||
|
backend->implementations.emplace_back(ref);
|
||||||
|
ref->self = ref;
|
||||||
|
} else {
|
||||||
|
backend->log(AQ_LOG_ERROR, std::format("Unknown backend id: {}", (int)b.backendType));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return backend;
|
return backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
Aquamarine::CBackend::~CBackend() {
|
Aquamarine::CBackend::~CBackend() {
|
||||||
log(AQ_LOG_DEBUG, "Bye world!\n");
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Aquamarine::CBackend::start() {
|
bool Aquamarine::CBackend::start() {
|
||||||
log(AQ_LOG_DEBUG, "Starting world!\n");
|
log(AQ_LOG_DEBUG, "Starting the Aquamarine backend!");
|
||||||
|
|
||||||
|
bool fallback = false;
|
||||||
|
int started = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < implementations.size(); ++i) {
|
||||||
|
const bool ok = implementations.at(i)->start();
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
log(AQ_LOG_ERROR, std::format("Requested backend ({}) could not start, enabling fallbacks", backendTypeToName(implementationOptions.at(i).backendType)));
|
||||||
|
fallback = true;
|
||||||
|
if (implementationOptions.at(i).backendRequestMode == AQ_BACKEND_REQUEST_MANDATORY) {
|
||||||
|
log(AQ_LOG_CRITICAL,
|
||||||
|
std::format("Requested backend ({}) could not start and it's mandatory, cannot continue!", backendTypeToName(implementationOptions.at(i).backendType)));
|
||||||
|
implementations.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
started++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (implementations.empty() || started <= 0) {
|
||||||
|
log(AQ_LOG_CRITICAL, "No backend could be opened. Make sure there was a correct backend passed to CBackend, and that your environment supports at least one of them.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// erase failed impls
|
||||||
|
std::erase_if(implementations, [](const auto& i) { return i->pollFD() < 0; });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,3 +96,63 @@ void Aquamarine::CBackend::log(eBackendLogLevel level, const std::string& msg) {
|
||||||
|
|
||||||
options.logFunction(level, msg);
|
options.logFunction(level, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Aquamarine::CBackend::enterLoop() {
|
||||||
|
std::vector<pollfd> pollFDs;
|
||||||
|
|
||||||
|
for (auto& i : implementations) {
|
||||||
|
auto fd = i->pollFD();
|
||||||
|
|
||||||
|
pollFDs.emplace_back(pollfd{.fd = fd, .events = POLLIN, .revents = 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread pollThr([this, &pollFDs]() {
|
||||||
|
int ret = 0;
|
||||||
|
while (1) {
|
||||||
|
ret = poll(pollFDs.data(), pollFDs.size(), 5000 /* 5 seconds, reasonable. It's because we might need to terminate */);
|
||||||
|
if (ret < 0) {
|
||||||
|
log(AQ_LOG_CRITICAL, std::format("Polling fds failed with {}", errno));
|
||||||
|
terminate = true;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pollFDs.size(); ++i) {
|
||||||
|
if (pollFDs[i].revents & POLLHUP) {
|
||||||
|
log(AQ_LOG_CRITICAL, std::format("disconnected from pollfd {}", i));
|
||||||
|
terminate = true;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terminate)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
std::lock_guard<std::mutex> lg(m_sEventLoopInternals.loopRequestMutex);
|
||||||
|
m_sEventLoopInternals.shouldProcess = true;
|
||||||
|
m_sEventLoopInternals.loopSignal.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
m_sEventLoopInternals.loopRequestMutex.unlock(); // unlock, we are ready to take events
|
||||||
|
|
||||||
|
std::unique_lock lk(m_sEventLoopInternals.loopMutex);
|
||||||
|
if (m_sEventLoopInternals.shouldProcess == false) // avoid a lock if a thread managed to request something already since we .unlock()ed
|
||||||
|
m_sEventLoopInternals.loopSignal.wait_for(lk, std::chrono::seconds(5), [this] { return m_sEventLoopInternals.shouldProcess == true; }); // wait for events
|
||||||
|
|
||||||
|
m_sEventLoopInternals.loopRequestMutex.lock(); // lock incoming events
|
||||||
|
|
||||||
|
if (terminate)
|
||||||
|
break;
|
||||||
|
|
||||||
|
m_sEventLoopInternals.shouldProcess = false;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lg(m_sEventLoopInternals.eventLock);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pollFDs.size(); ++i) {
|
||||||
|
implementations.at(i)->dispatchEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
265
src/backend/Wayland.cpp
Normal file
265
src/backend/Wayland.cpp
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
#include <aquamarine/backend/Wayland.hpp>
|
||||||
|
#include <wayland.hpp>
|
||||||
|
#include <xdg-shell.hpp>
|
||||||
|
|
||||||
|
using namespace Aquamarine;
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
using namespace Hyprutils::Math;
|
||||||
|
#define SP CSharedPointer
|
||||||
|
|
||||||
|
Aquamarine::CWaylandBackend::~CWaylandBackend() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
eBackendType Aquamarine::CWaylandBackend::type() {
|
||||||
|
return AQ_BACKEND_WAYLAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandBackend::CWaylandBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend_) : backend(backend_) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Aquamarine::CWaylandBackend::start() {
|
||||||
|
backend->log(AQ_LOG_DEBUG, "Starting the Wayland backend!");
|
||||||
|
|
||||||
|
waylandState.display = wl_display_connect(nullptr);
|
||||||
|
|
||||||
|
if (!waylandState.display) {
|
||||||
|
backend->log(AQ_LOG_ERROR, "Wayland backend cannot start: wl_display_connect failed (is a wayland compositor running?)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
waylandState.registry = makeShared<CWlRegistry>((wl_proxy*)wl_display_get_registry(waylandState.display));
|
||||||
|
|
||||||
|
backend->log(AQ_LOG_DEBUG, std::format("Got registry at 0x{:x}", (uintptr_t)waylandState.registry->resource()));
|
||||||
|
|
||||||
|
waylandState.registry->setGlobal([this](CWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
|
||||||
|
backend->log(AQ_LOG_TRACE, std::format(" | received global: {} (version {}) with id {}", name, version, id));
|
||||||
|
|
||||||
|
const std::string NAME = name;
|
||||||
|
|
||||||
|
if (NAME == "wl_seat") {
|
||||||
|
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 9, id));
|
||||||
|
waylandState.seat = makeShared<CWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_seat_interface, 9));
|
||||||
|
initSeat();
|
||||||
|
} else if (NAME == "xdg_wm_base") {
|
||||||
|
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 6, id));
|
||||||
|
waylandState.xdg = makeShared<CXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &xdg_wm_base_interface, 6));
|
||||||
|
initShell();
|
||||||
|
} else if (NAME == "wl_compositor") {
|
||||||
|
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 6, id));
|
||||||
|
waylandState.compositor = makeShared<CWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_compositor_interface, 6));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
waylandState.registry->setGlobalRemove([this](CWlRegistry* r, uint32_t id) { ; });
|
||||||
|
|
||||||
|
wl_display_roundtrip(waylandState.display);
|
||||||
|
|
||||||
|
if (!waylandState.xdg || !waylandState.compositor || !waylandState.seat) {
|
||||||
|
backend->log(AQ_LOG_ERROR, "Wayland backend cannot start: Missing protocols");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvents();
|
||||||
|
|
||||||
|
createOutput("WAYLAND1");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::CWaylandBackend::createOutput(const std::string& szName) {
|
||||||
|
outputs.emplace_back(SP<CWaylandOutput>(new CWaylandOutput(szName, self)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int Aquamarine::CWaylandBackend::pollFD() {
|
||||||
|
if (!waylandState.display)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return wl_display_get_fd(waylandState.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Aquamarine::CWaylandBackend::dispatchEvents() {
|
||||||
|
wl_display_flush(waylandState.display);
|
||||||
|
|
||||||
|
if (wl_display_prepare_read(waylandState.display) == 0) {
|
||||||
|
wl_display_read_events(waylandState.display);
|
||||||
|
wl_display_dispatch_pending(waylandState.display);
|
||||||
|
} else
|
||||||
|
wl_display_dispatch(waylandState.display);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
do {
|
||||||
|
ret = wl_display_dispatch_pending(waylandState.display);
|
||||||
|
wl_display_flush(waylandState.display);
|
||||||
|
} while (ret > 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandKeyboard::CWaylandKeyboard(Hyprutils::Memory::CSharedPointer<CWlKeyboard> keyboard_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) :
|
||||||
|
keyboard(keyboard_), backend(backend_) {
|
||||||
|
if (!keyboard->resource())
|
||||||
|
return;
|
||||||
|
|
||||||
|
backend->backend->log(AQ_LOG_DEBUG, "New wayland keyboard wl_keyboard");
|
||||||
|
|
||||||
|
keyboard->setKey([this](CWlKeyboard* r, uint32_t serial, uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) {
|
||||||
|
events.key.emit(SKeyEvent{
|
||||||
|
.timeMs = timeMs,
|
||||||
|
.key = key,
|
||||||
|
.pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
keyboard->setModifiers([this](CWlKeyboard* r, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
|
||||||
|
events.key.emit(SModifiersEvent{
|
||||||
|
.depressed = depressed,
|
||||||
|
.latched = latched,
|
||||||
|
.locked = locked,
|
||||||
|
.group = group,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandKeyboard::~CWaylandKeyboard() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Aquamarine::CWaylandKeyboard::getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandPointer::CWaylandPointer(Hyprutils::Memory::CSharedPointer<CWlPointer> pointer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) :
|
||||||
|
pointer(pointer_), backend(backend_) {
|
||||||
|
if (!pointer->resource())
|
||||||
|
return;
|
||||||
|
|
||||||
|
backend->backend->log(AQ_LOG_DEBUG, "New wayland pointer wl_pointer");
|
||||||
|
|
||||||
|
pointer->setMotion([this](CWlPointer* r, uint32_t serial, wl_fixed_t x, wl_fixed_t y) {
|
||||||
|
if (!backend->focusedOutput || !backend->focusedOutput->state->mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector2D local = {wl_fixed_to_double(x), wl_fixed_to_double(y)};
|
||||||
|
local = local / backend->focusedOutput->state->mode->pixelSize;
|
||||||
|
|
||||||
|
events.warp.emit(SWarpEvent{
|
||||||
|
.absolute = local,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
pointer->setEnter([this](CWlPointer* r, uint32_t serial, wl_proxy* surface, wl_fixed_t x, wl_fixed_t y) {
|
||||||
|
backend->lastEnterSerial = serial;
|
||||||
|
|
||||||
|
for (auto& o : backend->outputs) {
|
||||||
|
if (o->waylandState.surface->resource() != surface)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
backend->focusedOutput = o;
|
||||||
|
backend->backend->log(AQ_LOG_DEBUG, std::format("[wayland] focus changed: {}", o->name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pointer->setButton([this](CWlPointer* r, uint32_t serial, uint32_t timeMs, uint32_t button, wl_pointer_button_state state) {
|
||||||
|
events.button.emit(SButtonEvent{
|
||||||
|
.timeMs = timeMs,
|
||||||
|
.button = button,
|
||||||
|
.pressed = state == WL_POINTER_BUTTON_STATE_PRESSED,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
pointer->setAxis([this](CWlPointer* r, uint32_t timeMs, wl_pointer_axis axis, wl_fixed_t value) {
|
||||||
|
events.axis.emit(SAxisEvent{
|
||||||
|
.timeMs = timeMs,
|
||||||
|
.axis = axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ? AQ_POINTER_AXIS_HORIZONTAL : AQ_POINTER_AXIS_VERTICAL,
|
||||||
|
.value = wl_fixed_to_double(value),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
pointer->setFrame([this](CWlPointer* r) { events.frame.emit(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandPointer::~CWaylandPointer() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Aquamarine::CWaylandPointer::getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::CWaylandBackend::initSeat() {
|
||||||
|
waylandState.seat->setCapabilities([this](CWlSeat* r, wl_seat_capability cap) {
|
||||||
|
const bool HAS_KEYBOARD = ((uint32_t)cap) & WL_SEAT_CAPABILITY_KEYBOARD;
|
||||||
|
const bool HAS_POINTER = ((uint32_t)cap) & WL_SEAT_CAPABILITY_POINTER;
|
||||||
|
|
||||||
|
if (HAS_KEYBOARD && keyboards.empty())
|
||||||
|
keyboards.emplace_back(makeShared<CWaylandKeyboard>(SP<CWlKeyboard>(waylandState.seat->sendGetKeyboard()), self));
|
||||||
|
else if (!HAS_KEYBOARD && !keyboards.empty())
|
||||||
|
keyboards.clear();
|
||||||
|
|
||||||
|
if (HAS_POINTER && pointers.empty())
|
||||||
|
keyboards.emplace_back(makeShared<CWaylandKeyboard>(SP<CWlKeyboard>(waylandState.seat->sendGetKeyboard()), self));
|
||||||
|
else if (!HAS_POINTER && !keyboards.empty())
|
||||||
|
keyboards.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::CWaylandBackend::initShell() {
|
||||||
|
waylandState.xdg->setPing([](CXdgWmBase* r, uint32_t serial) { r->sendPong(serial); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandOutput::CWaylandOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : name(name_), backend(backend_) {
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
waylandState.surface = SP<CWlSurface>(backend->waylandState.compositor->sendCreateSurface());
|
||||||
|
|
||||||
|
if (!waylandState.surface->resource()) {
|
||||||
|
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no surface given. Errno: {}", name, errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
waylandState.xdgSurface = SP<CXdgSurface>(backend->waylandState.xdg->sendGetXdgSurface(waylandState.surface->resource()));
|
||||||
|
|
||||||
|
if (!waylandState.xdgSurface->resource()) {
|
||||||
|
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no xdgSurface given. Errno: {}", name, errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
waylandState.xdgSurface->setConfigure([this](CXdgSurface* r, uint32_t serial) {
|
||||||
|
backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: configure surface with {}", name, serial));
|
||||||
|
r->sendAckConfigure(serial);
|
||||||
|
});
|
||||||
|
|
||||||
|
waylandState.xdgToplevel = SP<CXdgToplevel>(waylandState.xdgSurface->sendGetToplevel());
|
||||||
|
|
||||||
|
if (!waylandState.xdgToplevel->resource()) {
|
||||||
|
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no xdgToplevel given. Errno: {}", name, errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
waylandState.xdgToplevel->setWmCapabilities(
|
||||||
|
[this](CXdgToplevel* r, wl_array* arr) { backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: wm_capabilities received", name)); });
|
||||||
|
|
||||||
|
waylandState.xdgToplevel->setConfigure([this](CXdgToplevel* r, int32_t w, int32_t h, wl_array* arr) {
|
||||||
|
backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: configure toplevel with {}x{}", name, w, h));
|
||||||
|
events.state.emit(SStateEvent{.size = {w, h}});
|
||||||
|
});
|
||||||
|
|
||||||
|
waylandState.surface->sendAttach(nullptr, 0, 0);
|
||||||
|
waylandState.surface->sendCommit();
|
||||||
|
|
||||||
|
backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: initialized", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Aquamarine::CWaylandOutput::~CWaylandOutput() {
|
||||||
|
if (waylandState.xdgToplevel)
|
||||||
|
waylandState.xdgToplevel->sendDestroy();
|
||||||
|
if (waylandState.xdgSurface)
|
||||||
|
waylandState.xdgSurface->sendDestroy();
|
||||||
|
if (waylandState.surface)
|
||||||
|
waylandState.surface->sendDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::CWaylandOutput::commit() {
|
||||||
|
;
|
||||||
|
}
|
41
src/buffer/Buffer.cpp
Normal file
41
src/buffer/Buffer.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include <aquamarine/buffer/Buffer.hpp>
|
||||||
|
#include "Shared.hpp"
|
||||||
|
|
||||||
|
using namespace Aquamarine;
|
||||||
|
|
||||||
|
SDMABUFAttrs Aquamarine::IBuffer::dmabuf() {
|
||||||
|
return SDMABUFAttrs{};
|
||||||
|
}
|
||||||
|
|
||||||
|
SSHMAttrs Aquamarine::IBuffer::shm() {
|
||||||
|
return SSHMAttrs{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<uint8_t*, uint32_t, size_t> Aquamarine::IBuffer::beginDataPtr(uint32_t flags) {
|
||||||
|
return {nullptr, 0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::IBuffer::endDataPtr() {
|
||||||
|
; // empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::IBuffer::sendRelease() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::IBuffer::lock() {
|
||||||
|
locks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::IBuffer::unlock() {
|
||||||
|
locks--;
|
||||||
|
|
||||||
|
ASSERT(locks >= 0);
|
||||||
|
|
||||||
|
if (locks <= 0)
|
||||||
|
sendRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Aquamarine::IBuffer::locked() {
|
||||||
|
return locks;
|
||||||
|
}
|
16
src/include/Shared.hpp
Normal file
16
src/include/Shared.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <format>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#define RASSERT(expr, reason, ...) \
|
||||||
|
if (!(expr)) { \
|
||||||
|
std::cout << std::format("\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \
|
||||||
|
std::format(reason, ##__VA_ARGS__), __LINE__, \
|
||||||
|
([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \
|
||||||
|
std::cout << "[Aquamarine] Assertion failed!"; \
|
||||||
|
raise(SIGABRT); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASSERT(expr) RASSERT(expr, "?")
|
41
tests/SimpleWindow.cpp
Normal file
41
tests/SimpleWindow.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include <aquamarine/backend/Backend.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static const char* aqLevelToString(Aquamarine::eBackendLogLevel level) {
|
||||||
|
switch (level) {
|
||||||
|
case Aquamarine::eBackendLogLevel::AQ_LOG_TRACE: return "TRACE";
|
||||||
|
case Aquamarine::eBackendLogLevel::AQ_LOG_DEBUG: return "DEBUG";
|
||||||
|
case Aquamarine::eBackendLogLevel::AQ_LOG_ERROR: return "ERROR";
|
||||||
|
case Aquamarine::eBackendLogLevel::AQ_LOG_WARNING: return "WARNING";
|
||||||
|
case Aquamarine::eBackendLogLevel::AQ_LOG_CRITICAL: return "CRITICAL";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
void aqLog(Aquamarine::eBackendLogLevel level, std::string msg) {
|
||||||
|
std::cout << "[AQ] [" << aqLevelToString(level) << "] " << msg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** envp) {
|
||||||
|
Aquamarine::SBackendOptions options;
|
||||||
|
options.logFunction = aqLog;
|
||||||
|
|
||||||
|
std::vector<Aquamarine::SBackendImplementationOptions> implementations;
|
||||||
|
Aquamarine::SBackendImplementationOptions waylandOptions;
|
||||||
|
waylandOptions.backendType = Aquamarine::eBackendType::AQ_BACKEND_WAYLAND;
|
||||||
|
waylandOptions.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_IF_AVAILABLE;
|
||||||
|
implementations.emplace_back(waylandOptions);
|
||||||
|
|
||||||
|
auto aqBackend = Aquamarine::CBackend::create(implementations, options);
|
||||||
|
|
||||||
|
if (!aqBackend->start()) {
|
||||||
|
std::cout << "Failed to start the aq backend\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
aqBackend->enterLoop();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue