control-center: add outputs pane
This commit is contained in:
parent
dee142b3bb
commit
d328655f8b
13 changed files with 1775 additions and 36 deletions
|
|
@ -744,8 +744,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
|||
wlr_output_heads: Default::default(),
|
||||
});
|
||||
let schedule = Rc::new(OutputSchedule::new(
|
||||
&state.ring,
|
||||
&state.eng,
|
||||
state,
|
||||
&connector_data,
|
||||
&persistent_state,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -1484,7 +1484,7 @@ impl ConfigProxyHandler {
|
|||
match connector {
|
||||
Some(c) => {
|
||||
let connector = self.get_output_node(c)?;
|
||||
connector.schedule.set_cursor_hz(hz);
|
||||
connector.schedule.set_cursor_hz(&self.state, hz);
|
||||
}
|
||||
_ => {
|
||||
let Some((hz, _)) = map_cursor_hz(hz) else {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
control_center::{
|
||||
cc_color_management::ColorManagementPane, cc_compositor::CompositorPane,
|
||||
cc_idle::IdlePane, cc_xwayland::XwaylandPane,
|
||||
cc_idle::IdlePane, cc_outputs::OutputsPane, cc_xwayland::XwaylandPane,
|
||||
},
|
||||
egui_adapter::egui_platform::{
|
||||
EggError, EggWindow, EggWindowOwner,
|
||||
|
|
@ -36,6 +36,7 @@ use {
|
|||
mod cc_color_management;
|
||||
mod cc_compositor;
|
||||
mod cc_idle;
|
||||
mod cc_outputs;
|
||||
mod cc_sidebar;
|
||||
mod cc_xwayland;
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ bitflags! {
|
|||
CCI_IDLE,
|
||||
CCI_COLOR_MANAGEMENT,
|
||||
CCI_XWAYLAND,
|
||||
CCI_OUTPUTS,
|
||||
}
|
||||
|
||||
pub struct ControlCenter {
|
||||
|
|
@ -118,6 +120,7 @@ enum PaneType {
|
|||
Idle(IdlePane),
|
||||
ColorManagement(ColorManagementPane),
|
||||
Xwayland(XwaylandPane),
|
||||
Outputs(Box<OutputsPane>),
|
||||
}
|
||||
|
||||
struct CcBehavior<'a> {
|
||||
|
|
@ -140,6 +143,7 @@ impl Pane {
|
|||
PaneType::Idle(v) => v.title(res),
|
||||
PaneType::ColorManagement(v) => v.title(res),
|
||||
PaneType::Xwayland(v) => v.title(res),
|
||||
PaneType::Outputs(v) => v.title(res),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,6 +153,7 @@ impl Pane {
|
|||
PaneType::Idle(p) => p.show(ui),
|
||||
PaneType::ColorManagement(p) => p.show(ui),
|
||||
PaneType::Xwayland(p) => p.show(behavior, ui),
|
||||
PaneType::Outputs(p) => p.show(&mut self.ps, ui),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -160,6 +165,7 @@ impl PaneType {
|
|||
PaneType::Idle(_) => CCI_IDLE,
|
||||
PaneType::ColorManagement(_) => CCI_COLOR_MANAGEMENT,
|
||||
PaneType::Xwayland(_) => CCI_XWAYLAND,
|
||||
PaneType::Outputs(_) => CCI_OUTPUTS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -415,7 +421,6 @@ fn icon_label(icon: &str) -> Label {
|
|||
Label::new(icon).selectable(false)
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
fn grid_label(ui: &mut Ui, label: &str) {
|
||||
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
||||
ui.label(label);
|
||||
|
|
|
|||
1711
src/control_center/cc_outputs.rs
Normal file
1711
src/control_center/cc_outputs.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@ enum PaneName {
|
|||
Idle,
|
||||
ColorManagement,
|
||||
Xwayland,
|
||||
Outputs,
|
||||
}
|
||||
|
||||
impl PaneName {
|
||||
|
|
@ -21,6 +22,7 @@ impl PaneName {
|
|||
PaneName::Idle => "Idle",
|
||||
PaneName::ColorManagement => "Color Management",
|
||||
PaneName::Xwayland => "Xwayland",
|
||||
PaneName::Outputs => "Outputs",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +57,9 @@ impl ControlCenterInner {
|
|||
PaneName::Xwayland => {
|
||||
PaneType::Xwayland(self.create_xwayland_pane())
|
||||
}
|
||||
PaneName::Outputs => {
|
||||
PaneType::Outputs(Box::new(self.create_outputs_pane()))
|
||||
}
|
||||
};
|
||||
self.open(tree, ty);
|
||||
ui.ctx().request_repaint();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use {
|
|||
egui::{Color32, Rgba},
|
||||
};
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub trait Color32Ext {
|
||||
fn to_oklab(self) -> Oklab;
|
||||
fn to_oklch(self) -> Oklch;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ pub enum EggError {
|
|||
}
|
||||
|
||||
pub mod icons {
|
||||
#[expect(dead_code)]
|
||||
pub const ICON_ADD: &str = "\u{e145}";
|
||||
pub const ICON_CLOSE: &str = "\u{e5cd}";
|
||||
pub const ICON_DRAG_INDICATOR: &str = "\u{e945}";
|
||||
|
|
@ -119,7 +118,6 @@ pub mod icons {
|
|||
pub const ICON_OPEN_IN_NEW: &str = "\u{e89e}";
|
||||
#[expect(dead_code)]
|
||||
pub const ICON_PENDING: &str = "\u{ef64}";
|
||||
#[expect(dead_code)]
|
||||
pub const ICON_REMOVE: &str = "\u{e15b}";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,14 +105,13 @@ pub struct ReadOnlyHeadState {
|
|||
}
|
||||
|
||||
impl ReadOnlyHeadState {
|
||||
#[expect(dead_code)]
|
||||
pub fn borrow(&self) -> Ref<'_, HeadState> {
|
||||
self.state.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
impl HeadState {
|
||||
fn update_in_compositor_space(&mut self, wl_output: Option<GlobalName>) {
|
||||
pub fn update_in_compositor_space(&mut self, wl_output: Option<GlobalName>) {
|
||||
self.in_compositor_space = false;
|
||||
self.wl_output = None;
|
||||
if !self.connector_enabled {
|
||||
|
|
@ -131,7 +130,7 @@ impl HeadState {
|
|||
self.wl_output = wl_output;
|
||||
}
|
||||
|
||||
fn update_size(&mut self) {
|
||||
pub fn update_size(&mut self) {
|
||||
self.size =
|
||||
OutputNode::calculate_extents_(self.mode, self.transform, self.scale, self.position)
|
||||
.size();
|
||||
|
|
@ -213,7 +212,7 @@ pub enum HeadCommonError {
|
|||
}
|
||||
|
||||
pub struct HeadManagers {
|
||||
name: HeadName,
|
||||
pub name: HeadName,
|
||||
state: Rc<RefCell<HeadState>>,
|
||||
managers: CopyHashMap<(ClientId, JayHeadManagerSessionV1Id), Rc<Head>>,
|
||||
}
|
||||
|
|
@ -235,7 +234,6 @@ impl HeadManagers {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn state(&self) -> ReadOnlyHeadState {
|
||||
ReadOnlyHeadState {
|
||||
state: self.state.clone(),
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ impl JayRandrRequestHandler for JayRandr {
|
|||
let Some(c) = self.get_output_node(req.output) else {
|
||||
return Ok(());
|
||||
};
|
||||
c.schedule.set_cursor_hz(req.hz);
|
||||
c.schedule.set_cursor_hz(&self.state, req.hz);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use {
|
|||
crate::{
|
||||
async_engine::AsyncEngine,
|
||||
backend::HardwareCursor,
|
||||
control_center::CCI_OUTPUTS,
|
||||
ifs::wl_output::PersistentOutputState,
|
||||
io_uring::{IoUring, IoUringError},
|
||||
state::ConnectorData,
|
||||
state::{ConnectorData, State},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, cell_ext::CellExt, clonecell::CloneCell, errorfmt::ErrorFmt,
|
||||
numcell::NumCell,
|
||||
|
|
@ -51,8 +52,7 @@ pub struct OutputSchedule {
|
|||
|
||||
impl OutputSchedule {
|
||||
pub fn new(
|
||||
ring: &Rc<IoUring>,
|
||||
eng: &Rc<AsyncEngine>,
|
||||
state: &State,
|
||||
connector: &Rc<ConnectorData>,
|
||||
persistent: &Rc<PersistentOutputState>,
|
||||
) -> Self {
|
||||
|
|
@ -60,8 +60,8 @@ impl OutputSchedule {
|
|||
changed: Default::default(),
|
||||
run: Default::default(),
|
||||
connector: connector.clone(),
|
||||
ring: ring.clone(),
|
||||
eng: eng.clone(),
|
||||
ring: state.ring.clone(),
|
||||
eng: state.eng.clone(),
|
||||
vrr_enabled: Default::default(),
|
||||
hardware_cursor_change: Cell::new(Change::None),
|
||||
software_cursor_change: Cell::new(Change::None),
|
||||
|
|
@ -72,7 +72,7 @@ impl OutputSchedule {
|
|||
iteration: Default::default(),
|
||||
};
|
||||
if let Some(hz) = persistent.vrr_cursor_hz.get() {
|
||||
slf.set_cursor_hz(hz);
|
||||
slf.set_cursor_hz(state, hz);
|
||||
}
|
||||
slf
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ impl OutputSchedule {
|
|||
self.trigger();
|
||||
}
|
||||
|
||||
pub fn set_cursor_hz(&self, hz: f64) {
|
||||
pub fn set_cursor_hz(&self, state: &State, hz: f64) {
|
||||
let (hz, delta) = match map_cursor_hz(hz) {
|
||||
None => {
|
||||
log::warn!("Ignoring cursor frequency {hz}");
|
||||
|
|
@ -128,6 +128,7 @@ impl OutputSchedule {
|
|||
};
|
||||
self.persistent.vrr_cursor_hz.set(hz);
|
||||
self.connector.head_managers.handle_cursor_hz_change(hz);
|
||||
state.trigger_cci(CCI_OUTPUTS);
|
||||
self.cursor_delta_nsec.set(delta);
|
||||
self.trigger();
|
||||
}
|
||||
|
|
|
|||
28
src/state.rs
28
src/state.rs
|
|
@ -17,7 +17,8 @@ use {
|
|||
compositor::{LIBEI_SOCKET, LogLevel},
|
||||
config::ConfigProxy,
|
||||
control_center::{
|
||||
CCI_COLOR_MANAGEMENT, CCI_COMPOSITOR, CCI_IDLE, CCI_XWAYLAND, ControlCenters,
|
||||
CCI_COLOR_MANAGEMENT, CCI_COMPOSITOR, CCI_IDLE, CCI_OUTPUTS, CCI_XWAYLAND,
|
||||
ControlCenters,
|
||||
},
|
||||
copy_device::CopyDeviceRegistry,
|
||||
cpu_worker::CpuWorker,
|
||||
|
|
@ -493,30 +494,39 @@ impl ConnectorData {
|
|||
return;
|
||||
}
|
||||
*self.state.borrow_mut() = s.clone();
|
||||
if old.enabled != s.enabled {
|
||||
macro_rules! b {
|
||||
($expr:expr) => {{
|
||||
let e = $expr;
|
||||
if e {
|
||||
state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
e
|
||||
}};
|
||||
}
|
||||
if b!(old.enabled != s.enabled) {
|
||||
self.head_managers.handle_enabled_change(s.enabled);
|
||||
}
|
||||
if old.active != s.active {
|
||||
if b!(old.active != s.active) {
|
||||
self.head_managers.handle_active_change(s.active);
|
||||
}
|
||||
if old.non_desktop_override != s.non_desktop_override {
|
||||
if b!(old.non_desktop_override != s.non_desktop_override) {
|
||||
self.head_managers
|
||||
.handle_non_desktop_override_changed(s.non_desktop_override);
|
||||
}
|
||||
if old.vrr != s.vrr {
|
||||
if b!(old.vrr != s.vrr) {
|
||||
self.head_managers.handle_vrr_change(s.vrr);
|
||||
}
|
||||
if old.tearing != s.tearing {
|
||||
if b!(old.tearing != s.tearing) {
|
||||
self.head_managers.handle_tearing_enabled_change(s.tearing);
|
||||
}
|
||||
if old.format != s.format {
|
||||
if b!(old.format != s.format) {
|
||||
self.head_managers.handle_format_change(s.format);
|
||||
}
|
||||
if (old.color_space, old.eotf) != (s.color_space, s.eotf) {
|
||||
if b!((old.color_space, old.eotf) != (s.color_space, s.eotf)) {
|
||||
self.head_managers
|
||||
.handle_colors_change(s.color_space, s.eotf);
|
||||
}
|
||||
if old.mode != s.mode {
|
||||
if b!(old.mode != s.mode) {
|
||||
self.head_managers.handle_mode_change(s.mode);
|
||||
for head in self.wlr_output_heads.lock().values() {
|
||||
head.handle_mode_change(s.mode);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use {
|
|||
BackendConnectorState, BackendConnectorStateSerial, Connector, ConnectorEvent,
|
||||
ConnectorId, MonitorInfo,
|
||||
},
|
||||
control_center::CCI_OUTPUTS,
|
||||
format::XRGB8888,
|
||||
globals::GlobalName,
|
||||
ifs::{
|
||||
|
|
@ -108,6 +109,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
|||
for mgr in state.head_managers.lock().values() {
|
||||
mgr.announce(&data);
|
||||
}
|
||||
state.trigger_cci(CCI_OUTPUTS);
|
||||
if state.connectors.set(id, data).is_some() {
|
||||
panic!("Connector id has been reused");
|
||||
}
|
||||
|
|
@ -147,6 +149,7 @@ impl ConnectorHandler {
|
|||
self.data.handler.set(None);
|
||||
self.state.connectors.remove(&self.id);
|
||||
self.data.head_managers.handle_removed();
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
|
||||
async fn handle_connected(&self, info: MonitorInfo) {
|
||||
|
|
@ -162,6 +165,7 @@ impl ConnectorHandler {
|
|||
}
|
||||
self.data.connected.set(false);
|
||||
self.data.head_managers.handle_output_disconnected();
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
for head in self.data.wlr_output_heads.lock().drain_values() {
|
||||
head.handle_disconnected();
|
||||
}
|
||||
|
|
@ -213,12 +217,7 @@ impl ConnectorHandler {
|
|||
info.primaries,
|
||||
info.luminance,
|
||||
));
|
||||
let schedule = Rc::new(OutputSchedule::new(
|
||||
&self.state.ring,
|
||||
&self.state.eng,
|
||||
&self.data,
|
||||
&desired_state,
|
||||
));
|
||||
let schedule = Rc::new(OutputSchedule::new(&self.state, &self.data, &desired_state));
|
||||
let _schedule = self
|
||||
.state
|
||||
.eng
|
||||
|
|
@ -341,6 +340,7 @@ impl ConnectorHandler {
|
|||
self.data
|
||||
.head_managers
|
||||
.handle_output_connected(&output_data);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
self.state.wlr_output_managers.announce_head(&output_data);
|
||||
'outer: loop {
|
||||
while let Some(event) = self.data.connector.event() {
|
||||
|
|
@ -353,6 +353,7 @@ impl ConnectorHandler {
|
|||
}
|
||||
ConnectorEvent::FormatsChanged(formats) => {
|
||||
self.data.head_managers.handle_formats_change(&formats);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
on.global.formats.set(formats);
|
||||
}
|
||||
ConnectorEvent::State(state) => {
|
||||
|
|
@ -466,6 +467,7 @@ impl ConnectorHandler {
|
|||
self.data
|
||||
.head_managers
|
||||
.handle_output_connected(&output_data);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
self.state.wlr_output_managers.announce_head(&output_data);
|
||||
'outer: loop {
|
||||
while let Some(event) = self.data.connector.event() {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use {
|
|||
},
|
||||
client::ClientId,
|
||||
cmm::cmm_description::ColorDescription,
|
||||
control_center::CCI_OUTPUTS,
|
||||
cursor::KnownCursor,
|
||||
fixed::Fixed,
|
||||
gfx_api::{AcquireSync, BufferResv, GfxTexture, ReleaseSync},
|
||||
|
|
@ -243,6 +244,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_tearing_active_change(tearing);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -501,6 +503,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_scale_change(scale);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
for head in self.global.connector.wlr_output_heads.lock().values() {
|
||||
head.handle_new_scale(scale);
|
||||
}
|
||||
|
|
@ -873,6 +876,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_transform_change(transform);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
for head in self.global.connector.wlr_output_heads.lock().values() {
|
||||
head.hande_transform_change(transform);
|
||||
}
|
||||
|
|
@ -935,6 +939,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_position_size_change(self);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
|
||||
pub fn update_state(self: &Rc<Self>, old: BackendConnectorState, state: BackendConnectorState) {
|
||||
|
|
@ -989,6 +994,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_brightness_change(brightness);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1004,6 +1010,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_use_native_gamut_change(use_native_gamut);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1015,6 +1022,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_blend_space_change(blend_space);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
}
|
||||
fn find_stacked_at(
|
||||
|
|
@ -1480,6 +1488,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_vrr_mode_change(mode);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
for head in self.global.connector.wlr_output_heads.lock().values() {
|
||||
head.handle_vrr_mode_change(mode);
|
||||
}
|
||||
|
|
@ -1494,6 +1503,7 @@ impl OutputNode {
|
|||
.connector
|
||||
.head_managers
|
||||
.handle_tearing_mode_change(mode);
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1543,6 +1553,7 @@ impl OutputNode {
|
|||
|
||||
pub fn set_flip_margin(&self, margin_ns: u64) {
|
||||
self.flip_margin_ns.set(Some(margin_ns));
|
||||
self.state.trigger_cci(CCI_OUTPUTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue