fix: noconfirm auto-selects first AUR match
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user