feat: Wave A — boot DRM wait, D-Bus login1, Wayland wire fixes
Boot: greeter DRM wait window, pcid-spawner ordering, plan updated D-Bus: sessiond login1 manager extension (GetUser, ActivateSessionOnSeat, lock/unlock, terminate/kill), KDE activation files (ActivityManager, JobViewServer, ksmserver), plan v3.0 Wayland: proper little-endian/padded strings, SCM_RIGHTS fd passing, xdg_toplevel.configure fix, compositor-checker protocol probes Verified: bash -n, TOML parsed, sessiond 30/30 tests, compositor all tests pass w/ warnings denied.
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
# KIO — reduced real KIOCore build for Red Bear OS.
|
# KIO — reduced real KIOCore build for Red Bear OS.
|
||||||
#
|
#
|
||||||
# Honesty boundary:
|
# Honesty boundary:
|
||||||
# - KIOCORE_ONLY=ON, BUILD_WITH_QML=OFF, USE_DBUS=OFF stay intentional.
|
# - KIOCORE_ONLY=ON and BUILD_WITH_QML=OFF stay intentional.
|
||||||
|
# - USE_DBUS=ON is now enabled to expose more real KIOCore functionality.
|
||||||
# - QtNetwork is still unavailable on Redox, so KIOCore uses source-local
|
# - QtNetwork is still unavailable on Redox, so KIOCore uses source-local
|
||||||
# Redox compatibility headers for the small QHostInfo/QHostAddress surface it needs.
|
# Redox compatibility headers for the small QHostInfo/QHostAddress surface it needs.
|
||||||
# - This recipe no longer forges QtNetwork headers into the shared sysroot.
|
# - This recipe no longer forges QtNetwork headers into the shared sysroot.
|
||||||
@@ -17,6 +18,7 @@ dependencies = [
|
|||||||
"kf6-kcoreaddons",
|
"kf6-kcoreaddons",
|
||||||
"kf6-kconfig",
|
"kf6-kconfig",
|
||||||
"kf6-ki18n",
|
"kf6-ki18n",
|
||||||
|
"kf6-kdbusaddons",
|
||||||
"kf6-kjobwidgets",
|
"kf6-kjobwidgets",
|
||||||
"kf6-kservice",
|
"kf6-kservice",
|
||||||
"kf6-kbookmarks",
|
"kf6-kbookmarks",
|
||||||
@@ -62,7 +64,7 @@ cmake "${COOKBOOK_SOURCE}" \
|
|||||||
-DQT_SKIP_AUTO_PLUGIN_INCLUSION=ON \
|
-DQT_SKIP_AUTO_PLUGIN_INCLUSION=ON \
|
||||||
-DKIOCORE_ONLY=ON \
|
-DKIOCORE_ONLY=ON \
|
||||||
-DBUILD_WITH_QML=OFF \
|
-DBUILD_WITH_QML=OFF \
|
||||||
-DUSE_DBUS=OFF \
|
-DUSE_DBUS=ON \
|
||||||
-DWITH_X11=OFF \
|
-DWITH_X11=OFF \
|
||||||
-Wno-dev
|
-Wno-dev
|
||||||
|
|
||||||
|
|||||||
@@ -17,16 +17,37 @@ public:
|
|||||||
IPv6Protocol,
|
IPv6Protocol,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SpecialAddress {
|
||||||
|
Null,
|
||||||
|
Broadcast,
|
||||||
|
LocalHost,
|
||||||
|
LocalHostIPv6,
|
||||||
|
AnyIPv4,
|
||||||
|
AnyIPv6,
|
||||||
|
Any = AnyIPv4,
|
||||||
|
};
|
||||||
|
|
||||||
QHostAddress() = default;
|
QHostAddress() = default;
|
||||||
|
|
||||||
|
explicit QHostAddress(SpecialAddress address)
|
||||||
|
{
|
||||||
|
setAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
explicit QHostAddress(const QString &address)
|
explicit QHostAddress(const QString &address)
|
||||||
{
|
{
|
||||||
setAddress(address);
|
setAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit QHostAddress(quint32 ip4Address)
|
||||||
|
{
|
||||||
|
setAddress(ip4Address);
|
||||||
|
}
|
||||||
|
|
||||||
void setAddress(const QString &address)
|
void setAddress(const QString &address)
|
||||||
{
|
{
|
||||||
m_address = address;
|
m_address = address;
|
||||||
|
m_ipv4Address = 0;
|
||||||
|
|
||||||
if (address.isEmpty()) {
|
if (address.isEmpty()) {
|
||||||
m_protocol = UnknownNetworkLayerProtocol;
|
m_protocol = UnknownNetworkLayerProtocol;
|
||||||
@@ -39,6 +60,8 @@ public:
|
|||||||
|
|
||||||
if (inet_pton(AF_INET, utf8.constData(), ipv4) == 1) {
|
if (inet_pton(AF_INET, utf8.constData(), ipv4) == 1) {
|
||||||
m_protocol = IPv4Protocol;
|
m_protocol = IPv4Protocol;
|
||||||
|
m_ipv4Address = (static_cast<quint32>(ipv4[0]) << 24) | (static_cast<quint32>(ipv4[1]) << 16)
|
||||||
|
| (static_cast<quint32>(ipv4[2]) << 8) | static_cast<quint32>(ipv4[3]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,24 +73,96 @@ public:
|
|||||||
m_protocol = UnknownNetworkLayerProtocol;
|
m_protocol = UnknownNetworkLayerProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setAddress(SpecialAddress address)
|
||||||
|
{
|
||||||
|
switch (address) {
|
||||||
|
case Null:
|
||||||
|
clear();
|
||||||
|
break;
|
||||||
|
case Broadcast:
|
||||||
|
setAddress(QStringLiteral("255.255.255.255"));
|
||||||
|
break;
|
||||||
|
case LocalHost:
|
||||||
|
setAddress(QStringLiteral("127.0.0.1"));
|
||||||
|
break;
|
||||||
|
case LocalHostIPv6:
|
||||||
|
setAddress(QStringLiteral("::1"));
|
||||||
|
break;
|
||||||
|
case AnyIPv4:
|
||||||
|
setAddress(QStringLiteral("0.0.0.0"));
|
||||||
|
break;
|
||||||
|
case AnyIPv6:
|
||||||
|
setAddress(QStringLiteral("::"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAddress(quint32 ip4Address)
|
||||||
|
{
|
||||||
|
in_addr address = {};
|
||||||
|
address.s_addr = ip4Address;
|
||||||
|
|
||||||
|
char buffer[INET_ADDRSTRLEN] = {};
|
||||||
|
if (inet_ntop(AF_INET, &address, buffer, sizeof(buffer)) != nullptr) {
|
||||||
|
m_address = QString::fromUtf8(buffer);
|
||||||
|
m_protocol = IPv4Protocol;
|
||||||
|
m_ipv4Address = ip4Address;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_address.clear();
|
||||||
|
m_protocol = UnknownNetworkLayerProtocol;
|
||||||
|
m_ipv4Address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool isNull() const
|
bool isNull() const
|
||||||
{
|
{
|
||||||
return m_protocol == UnknownNetworkLayerProtocol;
|
return m_protocol == UnknownNetworkLayerProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLoopback() const
|
||||||
|
{
|
||||||
|
return m_address == QStringLiteral("127.0.0.1") || m_address == QStringLiteral("::1");
|
||||||
|
}
|
||||||
|
|
||||||
QString toString() const
|
QString toString() const
|
||||||
{
|
{
|
||||||
return m_address;
|
return m_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint32 toIPv4Address(bool *ok = nullptr) const
|
||||||
|
{
|
||||||
|
if (ok) {
|
||||||
|
*ok = m_protocol == IPv4Protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_protocol == IPv4Protocol ? m_ipv4Address : 0;
|
||||||
|
}
|
||||||
|
|
||||||
NetworkLayerProtocol protocol() const
|
NetworkLayerProtocol protocol() const
|
||||||
{
|
{
|
||||||
return m_protocol;
|
return m_protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const QHostAddress &other) const
|
||||||
|
{
|
||||||
|
return m_protocol == other.m_protocol && m_address == other.m_address && m_ipv4Address == other.m_ipv4Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const QHostAddress &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_address;
|
QString m_address;
|
||||||
NetworkLayerProtocol m_protocol = UnknownNetworkLayerProtocol;
|
NetworkLayerProtocol m_protocol = UnknownNetworkLayerProtocol;
|
||||||
|
quint32 m_ipv4Address = 0;
|
||||||
|
|
||||||
friend QDataStream &operator<<(QDataStream &stream, const QHostAddress &address)
|
friend QDataStream &operator<<(QDataStream &stream, const QHostAddress &address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ public:
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void abortHostLookup(int)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void setHostName(const QString &hostName)
|
void setHostName(const QString &hostName)
|
||||||
{
|
{
|
||||||
m_hostName = hostName;
|
m_hostName = hostName;
|
||||||
@@ -156,11 +160,22 @@ public:
|
|||||||
return m_errorString;
|
return m_errorString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLookupId(int lookupId)
|
||||||
|
{
|
||||||
|
m_lookupId = lookupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lookupId() const
|
||||||
|
{
|
||||||
|
return m_lookupId;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_hostName;
|
QString m_hostName;
|
||||||
QList<QHostAddress> m_addresses;
|
QList<QHostAddress> m_addresses;
|
||||||
HostInfoError m_error = UnknownError;
|
HostInfoError m_error = UnknownError;
|
||||||
QString m_errorString;
|
QString m_errorString;
|
||||||
|
int m_lookupId = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QHostInfo)
|
Q_DECLARE_METATYPE(QHostInfo)
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
#TODO: Kirigami — QtQuick lightweight UI framework. QML-heavy but required by KDE Plasma.
|
#TODO: Kirigami — build the real non-QML C++ core on Redox. Qt Quick, templates, examples, and autotests stay disabled until the Qt6 QML/Quick runtime surface is stronger.
|
||||||
# Real build requires Qt6Quick/QML runtime proof (qtdeclarative exports Qt6Quick metadata,
|
|
||||||
# but downstream QML-dependent build and runtime paths are insufficient). Stub provides
|
|
||||||
# cmake configs for dependency resolution only.
|
|
||||||
[source]
|
[source]
|
||||||
tar = "https://invent.kde.org/frameworks/kirigami/-/archive/v6.10.0/kirigami-v6.10.0.tar.gz"
|
tar = "https://invent.kde.org/frameworks/kirigami/-/archive/v6.10.0/kirigami-v6.10.0.tar.gz"
|
||||||
|
|
||||||
@@ -9,12 +6,7 @@ tar = "https://invent.kde.org/frameworks/kirigami/-/archive/v6.10.0/kirigami-v6.
|
|||||||
template = "custom"
|
template = "custom"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"qtbase",
|
"qtbase",
|
||||||
"qtdeclarative",
|
|
||||||
"kf6-extra-cmake-modules",
|
"kf6-extra-cmake-modules",
|
||||||
"kf6-kcoreaddons",
|
|
||||||
"kf6-ki18n",
|
|
||||||
"kf6-kconfig",
|
|
||||||
"kf6-kguiaddons",
|
|
||||||
]
|
]
|
||||||
script = """
|
script = """
|
||||||
DYNAMIC_INIT
|
DYNAMIC_INIT
|
||||||
@@ -27,44 +19,35 @@ for qtdir in plugins mkspecs metatypes modules; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
STAGE="${COOKBOOK_STAGE}/usr"
|
sed -i 's/COMPONENTS Core Gui Concurrent Qml Quick Qml Quick Qml Quick/COMPONENTS Core Gui Concurrent/' \
|
||||||
mkdir -p "${STAGE}/lib/cmake/KF6Kirigami"
|
"${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/dev/null || true
|
||||||
mkdir -p "${STAGE}/lib/cmake/KF6Kirigami2"
|
sed -i 's/^ find_package(Qt6QuickTest .*/# find_package(Qt6QuickTest disabled for Redox core-only build)/' \
|
||||||
|
"${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/dev/null || true
|
||||||
|
sed -i 's/^ add_subdirectory(templates)/# add_subdirectory(templates) # disabled for Redox core-only build/' \
|
||||||
|
"${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/dev/null || true
|
||||||
|
sed -i 's/^ add_subdirectory(autotests)/# add_subdirectory(autotests) # disabled for Redox core-only build/' \
|
||||||
|
"${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/dev/null || true
|
||||||
|
|
||||||
cat > "${STAGE}/lib/cmake/KF6Kirigami/KF6KirigamiConfig.cmake" << 'EOFCFG'
|
rm -f CMakeCache.txt
|
||||||
add_library(KF6::Kirigami INTERFACE)
|
rm -rf CMakeFiles
|
||||||
EOFCFG
|
|
||||||
|
|
||||||
cat > "${STAGE}/lib/cmake/KF6Kirigami/KF6KirigamiConfigVersion.cmake" << 'EOFVER'
|
cmake "${COOKBOOK_SOURCE}" \
|
||||||
set(PACKAGE_VERSION "6.10.0")
|
-DCMAKE_TOOLCHAIN_FILE="${COOKBOOK_ROOT}/local/recipes/qt/redox-toolchain.cmake" \
|
||||||
set(PACKAGE_VERSIONCompatible TRUE)
|
-DQT_HOST_PATH="${HOST_BUILD}" \
|
||||||
EOFVER
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_PREFIX_PATH="${COOKBOOK_SYSROOT}:${COOKBOOK_STAGE}/usr/lib/cmake" \
|
||||||
|
-DBUILD_TESTING=OFF \
|
||||||
|
-DBUILD_QCH=OFF \
|
||||||
|
-DBUILD_EXAMPLES=OFF \
|
||||||
|
-DUSE_DBUS=OFF \
|
||||||
|
-Wno-dev
|
||||||
|
|
||||||
cat > "${STAGE}/lib/cmake/KF6Kirigami/KF6KirigamiTargets.cmake" << 'EOFTGT'
|
cmake --build . -j${COOKBOOK_MAKE_JOBS}
|
||||||
add_library(KF6::Kirigami INTERFACE)
|
cmake --install . --prefix "${COOKBOOK_STAGE}/usr"
|
||||||
EOFTGT
|
|
||||||
|
|
||||||
cat > "${STAGE}/lib/cmake/KF6Kirigami2/KF6Kirigami2Config.cmake" << 'EOFCFG2'
|
for lib in "${COOKBOOK_STAGE}/usr/lib/"libKirigami*.so.* "${COOKBOOK_STAGE}/usr/lib/"libKF6*.so.*; do
|
||||||
add_library(KF6::Kirigami2 INTERFACE)
|
[ -f "${lib}" ] || continue
|
||||||
EOFCFG2
|
patchelf --remove-rpath "${lib}" 2>/dev/null || true
|
||||||
|
done
|
||||||
cat > "${STAGE}/lib/cmake/KF6Kirigami2/KF6Kirigami2ConfigVersion.cmake" << 'EOFVER2'
|
|
||||||
set(PACKAGE_VERSION "6.10.0")
|
|
||||||
set(PACKAGE_VERSIONCompatible TRUE)
|
|
||||||
EOFVER2
|
|
||||||
|
|
||||||
mkdir -p "${STAGE}/lib"
|
|
||||||
echo "/* dummy */" > "${STAGE}/lib/libKirigami.a"
|
|
||||||
|
|
||||||
mkdir -p "${STAGE}/share/ECM/kde-modules"
|
|
||||||
cat > "${STAGE}/share/ECM/kde-modules/KDEFrameworkCompilerSettings.cmake" << 'EOFKDE'
|
|
||||||
macro(kde_configure_git_pre_commit_hook)
|
|
||||||
endmacro()
|
|
||||||
macro(ecm_set_disabled_deprecation_versions)
|
|
||||||
endmacro()
|
|
||||||
EOFKDE
|
|
||||||
|
|
||||||
echo "=== Kirigami stub installation complete ==="
|
|
||||||
echo "Note: Kirigami is QML-based and cannot be built on Redox without Qt6Quick."
|
|
||||||
echo "Dummy cmake configs installed for dependency resolution."
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
+79
-24
@@ -66,11 +66,16 @@ fn read_wayland_string(data: &[u8], cursor: &mut usize) -> Result<String, String
|
|||||||
return Ok(String::new());
|
return Ok(String::new());
|
||||||
}
|
}
|
||||||
if *cursor + length > data.len() {
|
if *cursor + length > data.len() {
|
||||||
return Err(String::from("unexpected end of message while reading string"));
|
return Err(String::from(
|
||||||
|
"unexpected end of message while reading string",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes = &data[*cursor..*cursor + length];
|
let bytes = &data[*cursor..*cursor + length];
|
||||||
let string_len = bytes.iter().position(|byte| *byte == 0).unwrap_or(bytes.len());
|
let string_len = bytes
|
||||||
|
.iter()
|
||||||
|
.position(|byte| *byte == 0)
|
||||||
|
.unwrap_or(bytes.len());
|
||||||
*cursor += length;
|
*cursor += length;
|
||||||
while *cursor % 4 != 0 {
|
while *cursor % 4 != 0 {
|
||||||
*cursor += 1;
|
*cursor += 1;
|
||||||
@@ -139,11 +144,10 @@ impl WaylandProbe {
|
|||||||
iov_base: msg.as_mut_ptr().cast(),
|
iov_base: msg.as_mut_ptr().cast(),
|
||||||
iov_len: msg.len(),
|
iov_len: msg.len(),
|
||||||
};
|
};
|
||||||
let control_len = unsafe {
|
let control_len =
|
||||||
libc::CMSG_SPACE((fds.len() * mem::size_of::<i32>()) as u32) as usize
|
unsafe { libc::CMSG_SPACE((fds.len() * mem::size_of::<i32>()) as u32) as usize };
|
||||||
};
|
|
||||||
let mut control = vec![0u8; control_len];
|
let mut control = vec![0u8; control_len];
|
||||||
let mut header = libc::msghdr {
|
let header = libc::msghdr {
|
||||||
msg_name: std::ptr::null_mut(),
|
msg_name: std::ptr::null_mut(),
|
||||||
msg_namelen: 0,
|
msg_namelen: 0,
|
||||||
msg_iov: &mut iov,
|
msg_iov: &mut iov,
|
||||||
@@ -170,10 +174,17 @@ impl WaylandProbe {
|
|||||||
|
|
||||||
let written = unsafe { libc::sendmsg(self.stream.as_raw_fd(), &header, 0) };
|
let written = unsafe { libc::sendmsg(self.stream.as_raw_fd(), &header, 0) };
|
||||||
if written < 0 {
|
if written < 0 {
|
||||||
return Err(format!("sendmsg failed: {}", std::io::Error::last_os_error()));
|
return Err(format!(
|
||||||
|
"sendmsg failed: {}",
|
||||||
|
std::io::Error::last_os_error()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
if written as usize != msg.len() {
|
if written as usize != msg.len() {
|
||||||
return Err(format!("short sendmsg write: expected {}, got {}", msg.len(), written));
|
return Err(format!(
|
||||||
|
"short sendmsg write: expected {}, got {}",
|
||||||
|
msg.len(),
|
||||||
|
written
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -209,7 +220,13 @@ impl WaylandProbe {
|
|||||||
Ok(registry_id)
|
Ok(registry_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind(&mut self, registry_id: u32, name: u32, interface: &str, version: u32) -> Result<u32, String> {
|
fn bind(
|
||||||
|
&mut self,
|
||||||
|
registry_id: u32,
|
||||||
|
name: u32,
|
||||||
|
interface: &str,
|
||||||
|
version: u32,
|
||||||
|
) -> Result<u32, String> {
|
||||||
let new_id = self.alloc_id();
|
let new_id = self.alloc_id();
|
||||||
let mut payload = Vec::new();
|
let mut payload = Vec::new();
|
||||||
push_u32(&mut payload, name);
|
push_u32(&mut payload, name);
|
||||||
@@ -257,7 +274,9 @@ fn expect_shm_formats(probe: &mut WaylandProbe, shm_id: u32) -> Result<(), Strin
|
|||||||
payload.len()
|
payload.len()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
formats.push(u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]));
|
formats.push(u32::from_le_bytes([
|
||||||
|
payload[0], payload[1], payload[2], payload[3],
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !formats.contains(&0) || !formats.contains(&1) {
|
if !formats.contains(&0) || !formats.contains(&1) {
|
||||||
@@ -267,7 +286,11 @@ fn expect_shm_formats(probe: &mut WaylandProbe, shm_id: u32) -> Result<(), Strin
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_xdg_configure(probe: &mut WaylandProbe, toplevel_id: u32, xdg_surface_id: u32) -> Result<u32, String> {
|
fn expect_xdg_configure(
|
||||||
|
probe: &mut WaylandProbe,
|
||||||
|
toplevel_id: u32,
|
||||||
|
xdg_surface_id: u32,
|
||||||
|
) -> Result<u32, String> {
|
||||||
let (object_id, opcode, payload) = probe.read_message()?;
|
let (object_id, opcode, payload) = probe.read_message()?;
|
||||||
if object_id != toplevel_id || opcode != XDG_TOPLEVEL_CONFIGURE {
|
if object_id != toplevel_id || opcode != XDG_TOPLEVEL_CONFIGURE {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -276,18 +299,26 @@ fn expect_xdg_configure(probe: &mut WaylandProbe, toplevel_id: u32, xdg_surface_
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
if payload.len() < 12 {
|
if payload.len() < 12 {
|
||||||
return Err(format!("short xdg_toplevel.configure payload: {} bytes", payload.len()));
|
return Err(format!(
|
||||||
|
"short xdg_toplevel.configure payload: {} bytes",
|
||||||
|
payload.len()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let states_len = u32::from_le_bytes([payload[8], payload[9], payload[10], payload[11]]) as usize;
|
let states_len =
|
||||||
|
u32::from_le_bytes([payload[8], payload[9], payload[10], payload[11]]) as usize;
|
||||||
if payload.len() != 12 + states_len {
|
if payload.len() != 12 + states_len {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"invalid xdg_toplevel.configure payload length: {} (states_len={})",
|
"invalid xdg_toplevel.configure payload length: {} (states_len={})",
|
||||||
payload.len(), states_len
|
payload.len(),
|
||||||
|
states_len
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if states_len % 4 != 0 {
|
if states_len % 4 != 0 {
|
||||||
return Err(format!("invalid xdg_toplevel.configure states array length: {}", states_len));
|
return Err(format!(
|
||||||
|
"invalid xdg_toplevel.configure states array length: {}",
|
||||||
|
states_len
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (object_id, opcode, payload) = probe.read_message()?;
|
let (object_id, opcode, payload) = probe.read_message()?;
|
||||||
@@ -300,7 +331,9 @@ fn expect_xdg_configure(probe: &mut WaylandProbe, toplevel_id: u32, xdg_surface_
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]))
|
Ok(u32::from_le_bytes([
|
||||||
|
payload[0], payload[1], payload[2], payload[3],
|
||||||
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exercise_shm_pool(probe: &mut WaylandProbe, shm_id: u32, surface_id: u32) -> Result<(), String> {
|
fn exercise_shm_pool(probe: &mut WaylandProbe, shm_id: u32, surface_id: u32) -> Result<(), String> {
|
||||||
@@ -320,7 +353,10 @@ fn exercise_shm_pool(probe: &mut WaylandProbe, shm_id: u32, surface_id: u32) ->
|
|||||||
.map_err(|err| format!("failed to size temp SHM file: {err}"))?;
|
.map_err(|err| format!("failed to size temp SHM file: {err}"))?;
|
||||||
|
|
||||||
let mut file = file;
|
let mut file = file;
|
||||||
file.write_all(&[0x40, 0x40, 0xFF, 0xFF, 0x40, 0x40, 0xFF, 0xFF, 0x40, 0x40, 0xFF, 0xFF, 0x40, 0x40, 0xFF, 0xFF])
|
file.write_all(&[
|
||||||
|
0x40, 0x40, 0xFF, 0xFF, 0x40, 0x40, 0xFF, 0xFF, 0x40, 0x40, 0xFF, 0xFF, 0x40, 0x40, 0xFF,
|
||||||
|
0xFF,
|
||||||
|
])
|
||||||
.map_err(|err| format!("failed to seed temp SHM file: {err}"))?;
|
.map_err(|err| format!("failed to seed temp SHM file: {err}"))?;
|
||||||
|
|
||||||
let pool_id = probe.alloc_id();
|
let pool_id = probe.alloc_id();
|
||||||
@@ -363,7 +399,8 @@ fn exercise_shm_pool(probe: &mut WaylandProbe, shm_id: u32, surface_id: u32) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_wayland_socket() -> Result<(), String> {
|
fn check_wayland_socket() -> Result<(), String> {
|
||||||
let runtime_dir = std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp/run/redbear-greeter".into());
|
let runtime_dir =
|
||||||
|
std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp/run/redbear-greeter".into());
|
||||||
let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".into());
|
let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".into());
|
||||||
let socket_path = format!("{}/{}", runtime_dir, display);
|
let socket_path = format!("{}/{}", runtime_dir, display);
|
||||||
|
|
||||||
@@ -388,7 +425,11 @@ fn check_wayland_socket() -> Result<(), String> {
|
|||||||
expect_shm_formats(&mut probe, shm_id)?;
|
expect_shm_formats(&mut probe, shm_id)?;
|
||||||
|
|
||||||
let surface_id = probe.alloc_id();
|
let surface_id = probe.alloc_id();
|
||||||
probe.send_message(compositor_id, WL_COMPOSITOR_CREATE_SURFACE, &surface_id.to_le_bytes())?;
|
probe.send_message(
|
||||||
|
compositor_id,
|
||||||
|
WL_COMPOSITOR_CREATE_SURFACE,
|
||||||
|
&surface_id.to_le_bytes(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let xdg_surface_id = probe.alloc_id();
|
let xdg_surface_id = probe.alloc_id();
|
||||||
let mut payload = Vec::new();
|
let mut payload = Vec::new();
|
||||||
@@ -397,9 +438,17 @@ fn check_wayland_socket() -> Result<(), String> {
|
|||||||
probe.send_message(xdg_wm_base_id, XDG_WM_BASE_GET_XDG_SURFACE, &payload)?;
|
probe.send_message(xdg_wm_base_id, XDG_WM_BASE_GET_XDG_SURFACE, &payload)?;
|
||||||
|
|
||||||
let toplevel_id = probe.alloc_id();
|
let toplevel_id = probe.alloc_id();
|
||||||
probe.send_message(xdg_surface_id, XDG_SURFACE_GET_TOPLEVEL, &toplevel_id.to_le_bytes())?;
|
probe.send_message(
|
||||||
|
xdg_surface_id,
|
||||||
|
XDG_SURFACE_GET_TOPLEVEL,
|
||||||
|
&toplevel_id.to_le_bytes(),
|
||||||
|
)?;
|
||||||
let serial = expect_xdg_configure(&mut probe, toplevel_id, xdg_surface_id)?;
|
let serial = expect_xdg_configure(&mut probe, toplevel_id, xdg_surface_id)?;
|
||||||
probe.send_message(xdg_surface_id, XDG_SURFACE_ACK_CONFIGURE, &serial.to_le_bytes())?;
|
probe.send_message(
|
||||||
|
xdg_surface_id,
|
||||||
|
XDG_SURFACE_ACK_CONFIGURE,
|
||||||
|
&serial.to_le_bytes(),
|
||||||
|
)?;
|
||||||
|
|
||||||
exercise_shm_pool(&mut probe, shm_id, surface_id)
|
exercise_shm_pool(&mut probe, shm_id, surface_id)
|
||||||
}
|
}
|
||||||
@@ -430,11 +479,17 @@ fn check_framebuffer() -> Result<(), String> {
|
|||||||
let addr = std::env::var("FRAMEBUFFER_ADDR").unwrap_or_default();
|
let addr = std::env::var("FRAMEBUFFER_ADDR").unwrap_or_default();
|
||||||
|
|
||||||
if width.is_empty() || height.is_empty() || addr.is_empty() {
|
if width.is_empty() || height.is_empty() || addr.is_empty() {
|
||||||
return Err("FRAMEBUFFER_* environment not set — bootloader didn't provide framebuffer".into());
|
return Err(
|
||||||
|
"FRAMEBUFFER_* environment not set — bootloader didn't provide framebuffer".into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let w: u32 = width.parse().map_err(|_| format!("invalid FRAMEBUFFER_WIDTH: {}", width))?;
|
let w: u32 = width
|
||||||
let h: u32 = height.parse().map_err(|_| format!("invalid FRAMEBUFFER_HEIGHT: {}", height))?;
|
.parse()
|
||||||
|
.map_err(|_| format!("invalid FRAMEBUFFER_WIDTH: {}", width))?;
|
||||||
|
let h: u32 = height
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| format!("invalid FRAMEBUFFER_HEIGHT: {}", height))?;
|
||||||
|
|
||||||
if w == 0 || h == 0 {
|
if w == 0 || h == 0 {
|
||||||
return Err("framebuffer dimensions are zero".into());
|
return Err("framebuffer dimensions are zero".into());
|
||||||
|
|||||||
Reference in New Issue
Block a user