Compare commits
No commits in common. "173d6ebd32bdc76bff066e8ca95de1faf2620082" and "9535ada4d011b7c2ce5e4f6656a49c285aff3245" have entirely different histories.
173d6ebd32
...
9535ada4d0
9 changed files with 108 additions and 105 deletions
|
|
@ -48,12 +48,23 @@ fn get_state_dir() -> Option<PathBuf> {
|
||||||
return Some(PathBuf::from(home).join(".local").join("state"));
|
return Some(PathBuf::from(home).join(".local").join("state"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(state_dir) = dirs::state_dir() {
|
dirs::state_dir()
|
||||||
return Some(state_dir);
|
}
|
||||||
|
|
||||||
|
/// Get the data directory, with Flatpak sandbox support.
|
||||||
|
fn get_data_dir() -> Option<PathBuf> {
|
||||||
|
// Check if we're running in Flatpak
|
||||||
|
if env::var_os("FLATPAK_ID").is_some() {
|
||||||
|
// Try HOST_XDG_DATA_HOME first
|
||||||
|
if let Some(host_data) = env::var_os("HOST_XDG_DATA_HOME") {
|
||||||
|
return Some(PathBuf::from(host_data));
|
||||||
|
}
|
||||||
|
// Fallback: try to construct from HOME
|
||||||
|
if let Some(home) = env::var_os("HOME") {
|
||||||
|
return Some(PathBuf::from(home).join(".local").join("share"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// On platforms without state_dir, fall back to ~/.local/state
|
dirs::data_dir()
|
||||||
let home_dir = dirs::home_dir()?;
|
|
||||||
Some(home_dir.join(".local").join(".state"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "subscription")]
|
#[cfg(feature = "subscription")]
|
||||||
|
|
@ -316,6 +327,40 @@ impl Config {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get data for the given application name and config version.
|
||||||
|
/// pub fn new_state(name: &str, version: u64) -> Result<Self, Error> {
|
||||||
|
pub fn new_data(name: &str, version: u64) -> Result<Self, Error> {
|
||||||
|
Self::new_data_inner(name, version, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_data_inner(
|
||||||
|
name: &str,
|
||||||
|
version: u64,
|
||||||
|
look_for_previous: bool,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
// Look for [name]/v[version]
|
||||||
|
let path = sanitize_name(name)?.join(format!("v{}", version));
|
||||||
|
|
||||||
|
// Get libcosmic user data directory
|
||||||
|
let mut user_path = get_data_dir().ok_or(Error::NoConfigDirectory)?;
|
||||||
|
user_path.push("cosmic");
|
||||||
|
user_path.push(path);
|
||||||
|
// Create new data directory if not found.
|
||||||
|
fs::create_dir_all(&user_path)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
system_path: None,
|
||||||
|
user_path: Some(user_path),
|
||||||
|
previous: if version > 1 && look_for_previous {
|
||||||
|
Self::new_data_inner(name, version - 1, false)
|
||||||
|
.ok()
|
||||||
|
.map(Box::new)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Start a transaction (to set multiple configs at the same time)
|
// Start a transaction (to set multiple configs at the same time)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transaction(&self) -> ConfigTransaction<'_> {
|
pub fn transaction(&self) -> ConfigTransaction<'_> {
|
||||||
|
|
|
||||||
|
|
@ -88,4 +88,7 @@ pub fn main() {
|
||||||
|
|
||||||
println!("Testing state");
|
println!("Testing state");
|
||||||
test_config(Config::new_state("com.system76.Example", 1).unwrap());
|
test_config(Config::new_state("com.system76.Example", 1).unwrap());
|
||||||
|
|
||||||
|
println!("Testing data");
|
||||||
|
test_config(Config::new_data("com.system76.Example", 1).unwrap());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ pub enum Message {
|
||||||
WindowClose,
|
WindowClose,
|
||||||
Surface(cosmic::surface::Action),
|
Surface(cosmic::surface::Action),
|
||||||
ToggleHideContent,
|
ToggleHideContent,
|
||||||
ToggleSomeAction,
|
|
||||||
WindowNew,
|
WindowNew,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +82,6 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
||||||
tracing::error!("Clicked {message:?}");
|
|
||||||
match message {
|
match message {
|
||||||
Message::Clicked => {
|
Message::Clicked => {
|
||||||
self.button_label = format!("Clicked {message:?}");
|
self.button_label = format!("Clicked {message:?}");
|
||||||
|
|
@ -93,10 +91,9 @@ impl cosmic::Application for App {
|
||||||
cosmic::app::Action::Surface(action),
|
cosmic::app::Action::Surface(action),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Message::WindowClose
|
Message::WindowClose => {}
|
||||||
| Message::ToggleHideContent
|
Message::ToggleHideContent => {}
|
||||||
| Message::ToggleSomeAction
|
Message::WindowNew => {}
|
||||||
| Message::WindowNew => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::none()
|
Task::none()
|
||||||
|
|
@ -105,7 +102,7 @@ impl cosmic::Application for App {
|
||||||
/// Creates a view after each update.
|
/// Creates a view after each update.
|
||||||
fn view(&self) -> Element<'_, Self::Message> {
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
let widget = cosmic::widget::context_menu(
|
let widget = cosmic::widget::context_menu(
|
||||||
cosmic::widget::button::text(self.button_label.clone()).on_press(Message::Clicked),
|
cosmic::widget::button::text(self.button_label.to_string()).on_press(Message::Clicked),
|
||||||
self.context_menu(),
|
self.context_menu(),
|
||||||
)
|
)
|
||||||
.on_surface_action(Message::Surface);
|
.on_surface_action(Message::Surface);
|
||||||
|
|
@ -129,20 +126,12 @@ impl App {
|
||||||
menu::Item::Divider,
|
menu::Item::Divider,
|
||||||
menu::Item::Folder(
|
menu::Item::Folder(
|
||||||
"View",
|
"View",
|
||||||
vec![
|
vec![menu::Item::CheckBox(
|
||||||
menu::Item::CheckBox(
|
"Hide content",
|
||||||
"Hide content",
|
None,
|
||||||
None,
|
self.hide_content,
|
||||||
self.hide_content,
|
ContextMenuAction::ToggleHideContent,
|
||||||
ContextMenuAction::ToggleHideContent,
|
)],
|
||||||
),
|
|
||||||
menu::Item::CheckBox(
|
|
||||||
"Test content",
|
|
||||||
None,
|
|
||||||
self.hide_content,
|
|
||||||
ContextMenuAction::ToggleSomeAction,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
menu::Item::Divider,
|
menu::Item::Divider,
|
||||||
menu::Item::Button("Quit", None, ContextMenuAction::WindowClose),
|
menu::Item::Button("Quit", None, ContextMenuAction::WindowClose),
|
||||||
|
|
@ -155,7 +144,6 @@ impl App {
|
||||||
pub enum ContextMenuAction {
|
pub enum ContextMenuAction {
|
||||||
WindowClose,
|
WindowClose,
|
||||||
ToggleHideContent,
|
ToggleHideContent,
|
||||||
ToggleSomeAction,
|
|
||||||
WindowNew,
|
WindowNew,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +153,6 @@ impl menu::Action for ContextMenuAction {
|
||||||
match self {
|
match self {
|
||||||
ContextMenuAction::WindowClose => Message::WindowClose,
|
ContextMenuAction::WindowClose => Message::WindowClose,
|
||||||
ContextMenuAction::ToggleHideContent => Message::ToggleHideContent,
|
ContextMenuAction::ToggleHideContent => Message::ToggleHideContent,
|
||||||
ContextMenuAction::ToggleSomeAction => Message::ToggleSomeAction,
|
|
||||||
ContextMenuAction::WindowNew => Message::WindowNew,
|
ContextMenuAction::WindowNew => Message::WindowNew,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use std::{env, process};
|
||||||
use cosmic::app::{Core, Settings, Task};
|
use cosmic::app::{Core, Settings, Task};
|
||||||
use cosmic::iced::alignment::{Horizontal, Vertical};
|
use cosmic::iced::alignment::{Horizontal, Vertical};
|
||||||
use cosmic::iced::keyboard::Key;
|
use cosmic::iced::keyboard::Key;
|
||||||
use cosmic::iced::{event, keyboard, window, Event, Length, Size, Subscription};
|
use cosmic::iced::{window, Length, Size};
|
||||||
use cosmic::widget::menu::action::MenuAction;
|
use cosmic::widget::menu::action::MenuAction;
|
||||||
use cosmic::widget::menu::key_bind::{KeyBind, Modifier};
|
use cosmic::widget::menu::key_bind::{KeyBind, Modifier};
|
||||||
use cosmic::widget::menu::{self, ItemHeight, ItemWidth};
|
use cosmic::widget::menu::{self, ItemHeight, ItemWidth};
|
||||||
|
|
@ -112,26 +112,6 @@ impl cosmic::Application for App {
|
||||||
vec![menu_bar(&self.config, &self.key_binds)]
|
vec![menu_bar(&self.config, &self.key_binds)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Self::Message> {
|
|
||||||
event::listen_with(|event, _status, _window_id| {
|
|
||||||
let Event::Keyboard(keyboard::Event::KeyPressed {
|
|
||||||
key,
|
|
||||||
modifiers,
|
|
||||||
physical_key,
|
|
||||||
..
|
|
||||||
}) = event
|
|
||||||
else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let key_binds = key_binds();
|
|
||||||
key_binds
|
|
||||||
.iter()
|
|
||||||
.find(|(key_bind, _)| key_bind.matches(modifiers, &key, Some(&physical_key)))
|
|
||||||
.map(|(_, action)| action.message())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle application events here.
|
/// Handle application events here.
|
||||||
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
||||||
match message {
|
match message {
|
||||||
|
|
|
||||||
2
iced
2
iced
|
|
@ -1 +1 @@
|
||||||
Subproject commit e891f34b3224b25fc4bdf286b3f9dba26c8abe5b
|
Subproject commit c34af044311c986e5f8458cf61bab2508aca48fa
|
||||||
|
|
@ -634,7 +634,6 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
shell.request_redraw();
|
|
||||||
#[cfg(wayland_platform)]
|
#[cfg(wayland_platform)]
|
||||||
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
|
self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
|
||||||
|
|
|
||||||
|
|
@ -650,13 +650,12 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
||||||
state.pressed = false;
|
state.pressed = false;
|
||||||
|
|
||||||
// process close condition
|
// process close condition
|
||||||
if state.open
|
if state
|
||||||
&& state
|
.view_cursor
|
||||||
.view_cursor
|
.position()
|
||||||
.position()
|
.unwrap_or_default()
|
||||||
.unwrap_or_default()
|
.distance(view_cursor.position().unwrap_or_default())
|
||||||
.distance(view_cursor.position().unwrap_or_default())
|
< 2.0
|
||||||
< 2.0
|
|
||||||
{
|
{
|
||||||
let is_inside = state.menu_states[..=if self.is_overlay {
|
let is_inside = state.menu_states[..=if self.is_overlay {
|
||||||
state.active_root.len().saturating_sub(1)
|
state.active_root.len().saturating_sub(1)
|
||||||
|
|
@ -1429,48 +1428,47 @@ where
|
||||||
state.view_cursor = view_cursor;
|
state.view_cursor = view_cursor;
|
||||||
|
|
||||||
// * remove invalid menus
|
// * remove invalid menus
|
||||||
if state.open {
|
|
||||||
let mut prev_bounds = std::iter::once(menu.bar_bounds)
|
|
||||||
.chain(
|
|
||||||
if menu.is_overlay {
|
|
||||||
state.menu_states[..state.menu_states.len().saturating_sub(1)].iter()
|
|
||||||
} else {
|
|
||||||
state.menu_states[..menu.depth].iter()
|
|
||||||
}
|
|
||||||
.map(|s| s.menu_bounds.children_bounds),
|
|
||||||
)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if menu.is_overlay && menu.close_condition.leave {
|
let mut prev_bounds = std::iter::once(menu.bar_bounds)
|
||||||
for i in (0..state.menu_states.len()).rev() {
|
.chain(
|
||||||
let mb = &state.menu_states[i].menu_bounds;
|
if menu.is_overlay {
|
||||||
|
state.menu_states[..state.menu_states.len().saturating_sub(1)].iter()
|
||||||
if mb.parent_bounds.contains(overlay_cursor)
|
} else {
|
||||||
|| menu.is_overlay && mb.children_bounds.contains(overlay_cursor)
|
state.menu_states[..menu.depth].iter()
|
||||||
|| mb.offset_bounds.contains(overlay_cursor)
|
|
||||||
|| (mb.check_bounds.contains(overlay_cursor)
|
|
||||||
&& prev_bounds.iter().all(|pvb| !pvb.contains(overlay_cursor)))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev_bounds.pop();
|
|
||||||
state.active_root.pop();
|
|
||||||
state.menu_states.pop();
|
|
||||||
}
|
}
|
||||||
} else if menu.is_overlay {
|
.map(|s| s.menu_bounds.children_bounds),
|
||||||
for i in (0..state.menu_states.len()).rev() {
|
)
|
||||||
let mb = &state.menu_states[i].menu_bounds;
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if mb.parent_bounds.contains(overlay_cursor)
|
if menu.is_overlay && menu.close_condition.leave {
|
||||||
|| mb.children_bounds.contains(overlay_cursor)
|
for i in (0..state.menu_states.len()).rev() {
|
||||||
|| prev_bounds.iter().all(|pvb| !pvb.contains(overlay_cursor))
|
let mb = &state.menu_states[i].menu_bounds;
|
||||||
{
|
|
||||||
break;
|
if mb.parent_bounds.contains(overlay_cursor)
|
||||||
}
|
|| menu.is_overlay && mb.children_bounds.contains(overlay_cursor)
|
||||||
prev_bounds.pop();
|
|| mb.offset_bounds.contains(overlay_cursor)
|
||||||
state.active_root.pop();
|
|| (mb.check_bounds.contains(overlay_cursor)
|
||||||
state.menu_states.pop();
|
&& prev_bounds.iter().all(|pvb| !pvb.contains(overlay_cursor)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
prev_bounds.pop();
|
||||||
|
state.active_root.pop();
|
||||||
|
state.menu_states.pop();
|
||||||
|
}
|
||||||
|
} else if menu.is_overlay {
|
||||||
|
for i in (0..state.menu_states.len()).rev() {
|
||||||
|
let mb = &state.menu_states[i].menu_bounds;
|
||||||
|
|
||||||
|
if mb.parent_bounds.contains(overlay_cursor)
|
||||||
|
|| mb.children_bounds.contains(overlay_cursor)
|
||||||
|
|| prev_bounds.iter().all(|pvb| !pvb.contains(overlay_cursor))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev_bounds.pop();
|
||||||
|
state.active_root.pop();
|
||||||
|
state.menu_states.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ pub enum Position {
|
||||||
#[default]
|
#[default]
|
||||||
Center,
|
Center,
|
||||||
Bottom,
|
Bottom,
|
||||||
Top,
|
|
||||||
Point(Point),
|
Point(Point),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,7 +259,6 @@ where
|
||||||
Position::Point(relative) => {
|
Position::Point(relative) => {
|
||||||
bounds.position() + Vector::new(relative.x, relative.y)
|
bounds.position() + Vector::new(relative.x, relative.y)
|
||||||
}
|
}
|
||||||
Position::Top => Point::new(bounds.x + bounds.width / 2.0, bounds.y),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Round position to prevent rendering issues
|
// Round position to prevent rendering issues
|
||||||
|
|
@ -355,12 +353,6 @@ where
|
||||||
position.x = (position.x - width / 2.0).clamp(0.0, bounds.width - width);
|
position.x = (position.x - width / 2.0).clamp(0.0, bounds.width - width);
|
||||||
position.y = (position.y - height / 2.0).clamp(0.0, bounds.height - height);
|
position.y = (position.y - height / 2.0).clamp(0.0, bounds.height - height);
|
||||||
}
|
}
|
||||||
Position::Top => {
|
|
||||||
let width = node.size().width;
|
|
||||||
let height = node.size().height;
|
|
||||||
position.x = (position.x - width / 2.0).clamp(0.0, bounds.width - width);
|
|
||||||
position.y = (position.y - height).clamp(0.0, bounds.height - height);
|
|
||||||
}
|
|
||||||
Position::Bottom => {
|
Position::Bottom => {
|
||||||
// Position is set to the center bottom of the widget
|
// Position is set to the center bottom of the widget
|
||||||
let width = node.size().width;
|
let width = node.size().width;
|
||||||
|
|
|
||||||
|
|
@ -1925,7 +1925,6 @@ where
|
||||||
..
|
..
|
||||||
}) = event
|
}) = event
|
||||||
{
|
{
|
||||||
shell.request_redraw();
|
|
||||||
state.focused_visible = true;
|
state.focused_visible = true;
|
||||||
return if *modifiers == keyboard::Modifiers::SHIFT {
|
return if *modifiers == keyboard::Modifiers::SHIFT {
|
||||||
self.focus_previous(state, shell);
|
self.focus_previous(state, shell);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue