fix: noconfirm auto-selects first AUR match

This commit is contained in:
2026-05-08 11:01:02 +01:00
parent d39cdc3fd9
commit 153cca6132
8056 changed files with 1983098 additions and 779 deletions
@@ -19,7 +19,7 @@
use std::collections::{HashMap, HashSet, VecDeque};
use std::io::{Read, Seek, SeekFrom, Write};
use std::mem;
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::{
atomic::{AtomicU32, Ordering},
@@ -60,6 +60,13 @@ mod drm_backend {
Ok(())
}
#[repr(C)]
#[derive(Clone, Copy)]
struct DrmResources {
connector_count: u32,
crtc_count: u32,
encoder_count: u32,
}
#[repr(C)]
struct DrmConnector {
connector_id: u32,
@@ -89,6 +96,15 @@ mod drm_backend {
type_: u32,
}
#[repr(C)]
#[derive(Clone, Copy)]
struct DrmGetEncoder {
encoder_id: u32,
encoder_type: u32,
crtc_id: u32,
possible_crtcs: u32,
possible_clones: u32,
}
#[repr(C)]
struct DrmCreateDumb {
height: u32,
width: u32,
@@ -127,7 +143,7 @@ mod drm_backend {
pub width: u32,
pub height: u32,
pub stride: u32,
pub buffers: Vec<Vec<u8>>,
pub buffers: Vec<(usize, usize)>,
fb_ids: Vec<u32>,
pub current: AtomicUsize,
_file: File,
@@ -138,9 +154,26 @@ mod drm_backend {
let mut file = File::open("/scheme/drm/card0").ok()?;
eprintln!("redbear-compositor: opened /scheme/drm/card0");
let mut resources_resp = vec![0u8; std::mem::size_of::<DrmResources>() + 32];
if drm_ioctl(&mut file, DRM_IOCTL_BASE, &[], &mut resources_resp).is_err() {
return None;
}
let resources = unsafe { *(resources_resp.as_ptr() as *const DrmResources) };
if resources.connector_count == 0 {
return None;
}
let connector_id = unsafe {
*(resources_resp
.as_ptr()
.add(std::mem::size_of::<DrmResources>()) as *const u32)
};
if connector_id == 0 {
return None;
}
// Get connector info
let mut conn: DrmConnector = unsafe { std::mem::zeroed() };
conn.connector_id = 0;
conn.connector_id = connector_id;
conn.mode_count = 1;
let mut req = vec![0u8; std::mem::size_of::<DrmConnector>()];
unsafe {
@@ -172,6 +205,34 @@ mod drm_backend {
let height = mode.vdisplay as u32;
eprintln!("redbear-compositor: DRM mode {}x{}", width, height);
let mut crtc_id = 1u32;
if conn.encoder_id != 0 {
let mut encoder_req: DrmGetEncoder = unsafe { std::mem::zeroed() };
encoder_req.encoder_id = conn.encoder_id;
let mut encoder_req_buf = vec![0u8; std::mem::size_of::<DrmGetEncoder>()];
unsafe {
std::ptr::copy_nonoverlapping(
&encoder_req as *const DrmGetEncoder as *const u8,
encoder_req_buf.as_mut_ptr(),
encoder_req_buf.len(),
);
}
let mut encoder_resp = vec![0u8; std::mem::size_of::<DrmGetEncoder>()];
if drm_ioctl(
&mut file,
DRM_IOCTL_MODE_GETCONNECTOR - 1,
&encoder_req_buf,
&mut encoder_resp,
)
.is_ok()
{
let encoder = unsafe { *(encoder_resp.as_ptr() as *const DrmGetEncoder) };
if encoder.crtc_id != 0 {
crtc_id = encoder.crtc_id;
}
}
}
// Create double-buffered framebuffers
let mut buffers = Vec::new();
let mut fb_ids = Vec::new();
@@ -213,7 +274,7 @@ mod drm_backend {
stride = dumb.pitch;
// Map dumb buffer
let map = DrmMapDumb {
let mut map = DrmMapDumb {
handle: dumb.handle,
pad: 0,
offset: 0,
@@ -230,8 +291,18 @@ mod drm_backend {
if drm_ioctl(&mut file, DRM_IOCTL_MODE_MAP_DUMB, &map_req, &mut map_resp).is_err() {
return None;
}
unsafe {
std::ptr::copy_nonoverlapping(
map_resp.as_ptr(),
&mut map as *mut DrmMapDumb as *mut u8,
std::mem::size_of::<DrmMapDumb>(),
);
}
let buf_size = dumb.size as usize;
buffers.push(vec![0u8; buf_size]);
if map.offset == 0 {
return None;
}
buffers.push((map.offset as usize, buf_size));
// Add framebuffer
let mut addfb = DrmAddFb {
@@ -271,10 +342,10 @@ mod drm_backend {
// Set CRTC with first framebuffer
let mut setcrtc: DrmSetCrtc = unsafe { std::mem::zeroed() };
setcrtc.crtc_id = 0;
setcrtc.crtc_id = crtc_id;
setcrtc.fb_handle = fb_ids[0];
setcrtc.connector_count = 1;
setcrtc.connectors[0] = 0; // connector 0
setcrtc.connectors[0] = connector_id;
setcrtc.mode = *mode;
let mut setcrtc_req = vec![0u8; std::mem::size_of::<DrmSetCrtc>()];
unsafe {
@@ -289,8 +360,8 @@ mod drm_backend {
}
eprintln!(
"redbear-compositor: DRM output {}x{} stride={}",
width, height, stride
"redbear-compositor: DRM output {}x{} stride={} connector={} crtc={}",
width, height, stride, connector_id, crtc_id
);
Some(DrmOutput {
width,
@@ -470,6 +541,70 @@ fn recv_with_rights(
Ok((read as usize, fds))
}
fn send_with_rights(
stream: &mut UnixStream,
object_id: u32,
opcode: u16,
payload: &[u8],
fds: &[RawFd],
) -> std::io::Result<()> {
let size = 8 + payload.len();
let mut msg = Vec::with_capacity(size);
push_u32(&mut msg, object_id);
push_u32(&mut msg, ((size as u32) << 16) | u32::from(opcode));
msg.extend_from_slice(payload);
if fds.is_empty() {
stream.write_all(&msg)?;
return Ok(());
}
let mut iov = libc::iovec {
iov_base: msg.as_mut_ptr().cast(),
iov_len: msg.len(),
};
let control_len = unsafe { libc::CMSG_SPACE((fds.len() * mem::size_of::<RawFd>()) as u32) as usize };
let mut control = vec![0u8; control_len];
let header = libc::msghdr {
msg_name: std::ptr::null_mut(),
msg_namelen: 0,
msg_iov: &mut iov,
msg_iovlen: 1,
msg_control: control.as_mut_ptr().cast(),
msg_controllen: control.len(),
msg_flags: 0,
};
unsafe {
let cmsg = libc::CMSG_FIRSTHDR(&header);
if cmsg.is_null() {
return Err(std::io::Error::other("failed to allocate SCM_RIGHTS header"));
}
(*cmsg).cmsg_level = libc::SOL_SOCKET;
(*cmsg).cmsg_type = libc::SCM_RIGHTS;
(*cmsg).cmsg_len = libc::CMSG_LEN((fds.len() * mem::size_of::<RawFd>()) as u32) as _;
std::ptr::copy_nonoverlapping(
fds.as_ptr().cast::<u8>(),
libc::CMSG_DATA(cmsg).cast::<u8>(),
fds.len() * mem::size_of::<RawFd>(),
);
}
let written = unsafe { libc::sendmsg(stream.as_raw_fd(), &header, 0) };
if written < 0 {
return Err(std::io::Error::last_os_error());
}
if written as usize != msg.len() {
return Err(std::io::Error::other(format!(
"short sendmsg write: expected {}, got {}",
msg.len(),
written
)));
}
Ok(())
}
const WL_DISPLAY_SYNC: u16 = 0;
const WL_DISPLAY_GET_REGISTRY: u16 = 1;
// Protocol constant: reserved for future implementation.
@@ -559,6 +694,10 @@ const WL_SEAT_NAME: u16 = 1;
const WL_POINTER_RELEASE: u16 = 0;
const WL_KEYBOARD_RELEASE: u16 = 0;
const WL_TOUCH_RELEASE: u16 = 0;
const WL_KEYBOARD_MODIFIERS: u16 = 4;
const WL_KEYBOARD_REPEAT_INFO: u16 = 5;
const WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: u32 = 0;
const WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE: u16 = 0;
const WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE: u16 = 1;
@@ -737,16 +876,6 @@ impl Compositor {
},
Global {
name: 7,
interface: "wl_data_device_manager".into(),
version: 3,
},
Global {
name: 8,
interface: "wl_subcompositor".into(),
version: 1,
},
Global {
name: 9,
interface: "wl_fixes".into(),
version: 2,
},
@@ -1336,6 +1465,10 @@ impl Compositor {
if let Some(client) = clients.get_mut(&client_id) {
client.objects.insert(new_id, object_type);
}
drop(clients);
if opcode == WL_SEAT_GET_KEYBOARD {
self.send_keyboard_setup(stream, new_id);
}
}
}
WL_SEAT_RELEASE => {
@@ -1781,7 +1914,7 @@ impl Compositor {
fb_stride = drm.stride as usize;
let idx = (drm.current.load(std::sync::atomic::Ordering::Relaxed) + 1)
% drm.buffers.len().max(1);
fb_ptr = drm.buffers[idx].as_mut_ptr();
fb_ptr = drm.buffers[idx].0 as *mut u8;
} else {
let mut fb = self.fb_data.lock().unwrap();
fb_stride = self.fb_stride as usize;
@@ -1928,11 +2061,11 @@ impl Compositor {
}
fn send_seat_capabilities(&self, stream: &mut UnixStream, seat_id: u32, version: u32) {
// wl_seat.capabilities — advertise pointer so Qt creates a wl_pointer proxy
// wl_seat.capabilities — advertise pointer + keyboard for login UI.
{
let mut msg = Vec::with_capacity(12);
push_header(&mut msg, seat_id, WL_SEAT_CAPABILITIES, 4);
push_u32(&mut msg, 0x1); // WL_SEAT_CAPABILITY_POINTER
push_u32(&mut msg, 0x3); // WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD
let _ = stream.write_all(&msg);
}
// wl_seat.name is v2+ and is required by Qt6 to fully initialize the seat.
@@ -1945,6 +2078,42 @@ impl Compositor {
let _ = stream.write_all(&msg);
}
}
fn send_keyboard_setup(&self, stream: &mut UnixStream, keyboard_id: u32) {
let fd = std::fs::File::open("/dev/null").ok().map(|file| file.into_raw_fd());
{
let mut payload = Vec::with_capacity(12);
push_u32(&mut payload, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP);
push_u32(&mut payload, 0);
push_u32(&mut payload, 0);
let fds = fd.iter().copied().collect::<Vec<_>>();
let _ = send_with_rights(stream, keyboard_id, WL_KEYBOARD_KEYMAP, &payload, &fds);
}
if let Some(fd) = fd {
let _ = unsafe { libc::close(fd) };
}
{
let mut msg = Vec::with_capacity(16);
push_header(&mut msg, keyboard_id, WL_KEYBOARD_REPEAT_INFO, 8);
push_i32(&mut msg, 0);
push_i32(&mut msg, 0);
let _ = stream.write_all(&msg);
}
{
let mut msg = Vec::with_capacity(28);
push_header(&mut msg, keyboard_id, WL_KEYBOARD_MODIFIERS, 20);
push_u32(&mut msg, self.next_serial());
push_u32(&mut msg, 0);
push_u32(&mut msg, 0);
push_u32(&mut msg, 0);
push_u32(&mut msg, 0);
let _ = stream.write_all(&msg);
}
}
}
fn main() {