feat(displays): add X11 scaling settings
This commit is contained in:
parent
47c6329645
commit
a5744e8bdb
2 changed files with 104 additions and 17 deletions
|
|
@ -10,15 +10,17 @@ use cosmic::iced::{time, Alignment, Length};
|
||||||
use cosmic::iced_widget::scrollable::{Direction, Properties, RelativeOffset};
|
use cosmic::iced_widget::scrollable::{Direction, Properties, RelativeOffset};
|
||||||
use cosmic::prelude::CollectionWidget;
|
use cosmic::prelude::CollectionWidget;
|
||||||
use cosmic::widget::{
|
use cosmic::widget::{
|
||||||
self, column, container, dropdown, list_column, segmented_button, tab_bar, toggler,
|
self, column, container, dropdown, list_column, segmented_button, tab_bar, text, toggler,
|
||||||
};
|
};
|
||||||
use cosmic::{command, Apply, Command, Element};
|
use cosmic::{command, Apply, Command, Element};
|
||||||
|
use cosmic_config::{ConfigGet, ConfigSet};
|
||||||
use cosmic_randr_shell::{List, Output, OutputKey, Transform};
|
use cosmic_randr_shell::{List, Output, OutputKey, Transform};
|
||||||
use cosmic_settings_page::{self as page, section, Section};
|
use cosmic_settings_page::{self as page, section, Section};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use slotmap::{Key, SecondaryMap, SlotMap};
|
use slotmap::{Key, SecondaryMap, SlotMap};
|
||||||
use std::{collections::BTreeMap, process::ExitStatus, sync::Arc};
|
use std::{collections::BTreeMap, process::ExitStatus, sync::Arc};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
static DPI_SCALES: &[u32] = &[50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300];
|
static DPI_SCALES: &[u32] = &[50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300];
|
||||||
static DPI_SCALE_LABELS: Lazy<Vec<String>> =
|
static DPI_SCALE_LABELS: Lazy<Vec<String>> =
|
||||||
|
|
@ -98,6 +100,7 @@ pub enum Message {
|
||||||
/// Available outputs from cosmic-randr.
|
/// Available outputs from cosmic-randr.
|
||||||
randr: Arc<Result<List, cosmic_randr_shell::Error>>,
|
randr: Arc<Result<List, cosmic_randr_shell::Error>>,
|
||||||
},
|
},
|
||||||
|
SetXwaylandDescaling(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Message> for app::Message {
|
impl From<Message> for app::Message {
|
||||||
|
|
@ -137,10 +140,22 @@ pub struct Page {
|
||||||
/// the instant the setting was changed.
|
/// the instant the setting was changed.
|
||||||
dialog_countdown: usize,
|
dialog_countdown: usize,
|
||||||
show_display_options: bool,
|
show_display_options: bool,
|
||||||
|
comp_config: cosmic_config::Config,
|
||||||
|
comp_config_descale_xwayland: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Page {
|
impl Default for Page {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let comp_config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap();
|
||||||
|
let comp_config_descale_xwayland =
|
||||||
|
comp_config.get("descale_xwayland").unwrap_or_else(|err| {
|
||||||
|
if !matches!(err, cosmic_config::Error::NoConfigDirectory) {
|
||||||
|
error!(?err, "Failed to read config 'descale_xwayland'");
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
list: List::default(),
|
list: List::default(),
|
||||||
display_tabs: segmented_button::SingleSelectModel::default(),
|
display_tabs: segmented_button::SingleSelectModel::default(),
|
||||||
|
|
@ -156,6 +171,8 @@ impl Default for Page {
|
||||||
dialog: None,
|
dialog: None,
|
||||||
dialog_countdown: 0,
|
dialog_countdown: 0,
|
||||||
show_display_options: true,
|
show_display_options: true,
|
||||||
|
comp_config,
|
||||||
|
comp_config_descale_xwayland,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +221,8 @@ impl page::Page<crate::pages::Message> for Page {
|
||||||
sections.insert(display_arrangement()),
|
sections.insert(display_arrangement()),
|
||||||
// Display configuration
|
// Display configuration
|
||||||
sections.insert(display_configuration()),
|
sections.insert(display_configuration()),
|
||||||
|
// Xwayland scaling options
|
||||||
|
sections.insert(legacy_applications()),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,6 +489,16 @@ impl Page {
|
||||||
fl!("orientation", "rotate-270"),
|
fl!("orientation", "rotate-270"),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::SetXwaylandDescaling(descale) => {
|
||||||
|
self.comp_config_descale_xwayland = descale;
|
||||||
|
if let Err(err) = self
|
||||||
|
.comp_config
|
||||||
|
.set("descale_xwayland", &self.comp_config_descale_xwayland)
|
||||||
|
{
|
||||||
|
error!(?err, "Failed to set config 'descale_xwayland'");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.last_pan = 0.5;
|
self.last_pan = 0.5;
|
||||||
|
|
@ -1018,28 +1047,28 @@ pub fn display_configuration() -> Section<crate::pages::Message> {
|
||||||
let active_output = &page.list.outputs[active_id];
|
let active_output = &page.list.outputs[active_id];
|
||||||
|
|
||||||
let display_options = (page.show_display_options && active_output.enabled).then(|| {
|
let display_options = (page.show_display_options && active_output.enabled).then(|| {
|
||||||
list_column()
|
vec![
|
||||||
.add(widget::settings::item(
|
widget::settings::item(
|
||||||
&descriptions[resolution],
|
&descriptions[resolution],
|
||||||
dropdown(
|
dropdown(
|
||||||
&page.cache.resolutions,
|
&page.cache.resolutions,
|
||||||
page.cache.resolution_selected,
|
page.cache.resolution_selected,
|
||||||
Message::Resolution,
|
Message::Resolution,
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
.add(widget::settings::item(
|
widget::settings::item(
|
||||||
&descriptions[refresh_rate],
|
&descriptions[refresh_rate],
|
||||||
dropdown(
|
dropdown(
|
||||||
&page.cache.refresh_rates,
|
&page.cache.refresh_rates,
|
||||||
page.cache.refresh_rate_selected,
|
page.cache.refresh_rate_selected,
|
||||||
Message::RefreshRate,
|
Message::RefreshRate,
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
.add(widget::settings::item(
|
widget::settings::item(
|
||||||
&descriptions[scale],
|
&descriptions[scale],
|
||||||
dropdown(&DPI_SCALE_LABELS, page.cache.scale_selected, Message::Scale),
|
dropdown(&DPI_SCALE_LABELS, page.cache.scale_selected, Message::Scale),
|
||||||
))
|
),
|
||||||
.add(widget::settings::item(
|
widget::settings::item(
|
||||||
&descriptions[orientation],
|
&descriptions[orientation],
|
||||||
dropdown(
|
dropdown(
|
||||||
&page.cache.orientations,
|
&page.cache.orientations,
|
||||||
|
|
@ -1053,10 +1082,11 @@ pub fn display_configuration() -> Section<crate::pages::Message> {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut content = column().spacing(theme.cosmic().space_m());
|
let mut content = column().spacing(theme.cosmic().space_xs());
|
||||||
|
|
||||||
if page.list.outputs.len() > 1 {
|
if page.list.outputs.len() > 1 {
|
||||||
let display_switcher = tab_bar::horizontal(&page.display_tabs)
|
let display_switcher = tab_bar::horizontal(&page.display_tabs)
|
||||||
|
|
@ -1073,7 +1103,7 @@ pub fn display_configuration() -> Section<crate::pages::Message> {
|
||||||
> 1
|
> 1
|
||||||
|| !active_output.enabled)
|
|| !active_output.enabled)
|
||||||
.then(|| {
|
.then(|| {
|
||||||
list_column()
|
let mut column = list_column()
|
||||||
.add(widget::settings::item(
|
.add(widget::settings::item(
|
||||||
&descriptions[enable_label],
|
&descriptions[enable_label],
|
||||||
toggler(None, active_output.enabled, Message::DisplayToggle),
|
toggler(None, active_output.enabled, Message::DisplayToggle),
|
||||||
|
|
@ -1084,17 +1114,68 @@ pub fn display_configuration() -> Section<crate::pages::Message> {
|
||||||
&page.mirror_menu,
|
&page.mirror_menu,
|
||||||
Message::Mirroring,
|
Message::Mirroring,
|
||||||
),
|
),
|
||||||
))
|
));
|
||||||
|
|
||||||
|
if let Some(items) = display_options {
|
||||||
|
for item in items {
|
||||||
|
column = column.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
column
|
||||||
});
|
});
|
||||||
|
|
||||||
content = content.push(display_switcher).push_maybe(display_enable);
|
content = content.push(display_switcher).push_maybe(display_enable);
|
||||||
|
} else {
|
||||||
|
content = content
|
||||||
|
.push(widget::text::heading(&descriptions[options_label]))
|
||||||
|
.push_maybe(display_options.map(|items| {
|
||||||
|
let mut column = list_column();
|
||||||
|
for item in items {
|
||||||
|
column = column.add(item);
|
||||||
|
}
|
||||||
|
column
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
content
|
content.apply(Element::from).map(pages::Message::Displays)
|
||||||
.push(widget::text::heading(&descriptions[options_label]))
|
})
|
||||||
.push_maybe(display_options)
|
}
|
||||||
|
|
||||||
|
pub fn legacy_applications() -> Section<crate::pages::Message> {
|
||||||
|
let mut descriptions = Slab::new();
|
||||||
|
|
||||||
|
let system = descriptions.insert(fl!("legacy-applications", "scaled-by-system"));
|
||||||
|
let system_desc = descriptions.insert(fl!("legacy-applications", "system-description"));
|
||||||
|
let native = descriptions.insert(fl!("legacy-applications", "scaled-natively"));
|
||||||
|
let native_desc = descriptions.insert(fl!("legacy-applications", "native-description"));
|
||||||
|
|
||||||
|
Section::default()
|
||||||
|
.title(fl!("legacy-applications"))
|
||||||
|
.descriptions(descriptions)
|
||||||
|
.view::<Page>(move |_binder, page, section| {
|
||||||
|
let descriptions = §ion.descriptions;
|
||||||
|
widget::settings::view_section(§ion.title)
|
||||||
|
.add(widget::settings::item_row(vec![widget::radio(
|
||||||
|
widget::column()
|
||||||
|
.push(text::body(&descriptions[system]))
|
||||||
|
.push(text::caption(&descriptions[system_desc])),
|
||||||
|
false,
|
||||||
|
Some(page.comp_config_descale_xwayland),
|
||||||
|
Message::SetXwaylandDescaling,
|
||||||
|
)
|
||||||
|
.into()]))
|
||||||
|
.add(widget::settings::item_row(vec![widget::radio(
|
||||||
|
widget::column()
|
||||||
|
.push(text::body(&descriptions[native]))
|
||||||
|
.push(text::caption(&descriptions[native_desc])),
|
||||||
|
true,
|
||||||
|
Some(page.comp_config_descale_xwayland),
|
||||||
|
Message::SetXwaylandDescaling,
|
||||||
|
)
|
||||||
|
.into()]))
|
||||||
.apply(Element::from)
|
.apply(Element::from)
|
||||||
.map(pages::Message::Displays)
|
.map(crate::pages::Message::Displays)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,12 @@ dialog = Dialog
|
||||||
.change-prompt = Settings changes will automatically revert in { $time } seconds.
|
.change-prompt = Settings changes will automatically revert in { $time } seconds.
|
||||||
.revert-settings = Revert Settings
|
.revert-settings = Revert Settings
|
||||||
|
|
||||||
|
legacy-applications = X11 Window System Application Scaling
|
||||||
|
.scaled-by-system = Scale all X11 Applications
|
||||||
|
.system-description = X11 applications will appear blurry on HiDPI screens.
|
||||||
|
.scaled-natively = Render X11 Applications at native resolution
|
||||||
|
.native-description = X11 applications that don't support scaling will be small when HiDPI displays are in use. Enable for games to utilize the full monitor resolution.
|
||||||
|
|
||||||
## Sound
|
## Sound
|
||||||
|
|
||||||
sound = Sound
|
sound = Sound
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue