fix: gate wayland features and add inline popover fallback
This commit is contained in:
parent
467998433c
commit
8b95675c9b
3 changed files with 85 additions and 23 deletions
106
src/main.rs
106
src/main.rs
|
|
@ -530,6 +530,7 @@ pub struct App {
|
||||||
segmented_button::Entity,
|
segmented_button::Entity,
|
||||||
Option<String>,
|
Option<String>,
|
||||||
widget::Id,
|
widget::Id,
|
||||||
|
cosmic::iced::Point,
|
||||||
)>,
|
)>,
|
||||||
#[cfg(feature = "password_manager")]
|
#[cfg(feature = "password_manager")]
|
||||||
password_mgr: password_manager::PasswordManager,
|
password_mgr: password_manager::PasswordManager,
|
||||||
|
|
@ -2437,14 +2438,14 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::CopyUrlByMenu => {
|
Message::CopyUrlByMenu => {
|
||||||
if let Some((_, _, _, ref link, _)) = self.context_menu_popup {
|
if let Some((_, _, _, ref link, _, _)) = self.context_menu_popup {
|
||||||
if let Some(url) = link.clone() {
|
if let Some(url) = link.clone() {
|
||||||
return Task::batch([clipboard::write(url), self.update_focus()]);
|
return Task::batch([clipboard::write(url), self.update_focus()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::LaunchUrlByMenu => {
|
Message::LaunchUrlByMenu => {
|
||||||
if let Some((_, _, _, ref link, _)) = self.context_menu_popup {
|
if let Some((_, _, _, ref link, _, _)) = self.context_menu_popup {
|
||||||
if let Some(url) = link.as_ref() {
|
if let Some(url) = link.as_ref() {
|
||||||
if let Err(err) = open::that_detached(url) {
|
if let Err(err) = open::that_detached(url) {
|
||||||
log::warn!("failed to open {:?}: {}", url, err);
|
log::warn!("failed to open {:?}: {}", url, err);
|
||||||
|
|
@ -2799,10 +2800,13 @@ impl Application for App {
|
||||||
Message::TabContextAction(entity, action) => {
|
Message::TabContextAction(entity, action) => {
|
||||||
// Close context menu popup
|
// Close context menu popup
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
if let Some((popup_id, _, _, _, _)) = self.context_menu_popup.take() {
|
if let Some((_popup_id, _, _, _, _, _)) = self.context_menu_popup.take() {
|
||||||
tasks.push(cosmic::task::message(Message::Surface(
|
#[cfg(feature = "wayland")]
|
||||||
cosmic::surface::action::destroy_popup(popup_id),
|
if is_wayland() {
|
||||||
)));
|
tasks.push(cosmic::task::message(Message::Surface(
|
||||||
|
cosmic::surface::action::destroy_popup(_popup_id),
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Also clear terminal context_menu state
|
// Also clear terminal context_menu state
|
||||||
if let Some(tab_model) = self.pane_model.active() {
|
if let Some(tab_model) = self.pane_model.active() {
|
||||||
|
|
@ -2815,13 +2819,17 @@ impl Application for App {
|
||||||
return cosmic::Task::batch(tasks);
|
return cosmic::Task::batch(tasks);
|
||||||
}
|
}
|
||||||
Message::TabContextMenu(pane, menu_state) => {
|
Message::TabContextMenu(pane, menu_state) => {
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
// Close existing context menu popup if any
|
// Close existing context menu popup if any
|
||||||
if let Some((popup_id, _, _, _, _)) = self.context_menu_popup.take() {
|
if let Some((_popup_id, _, _, _, _, _)) = self.context_menu_popup.take() {
|
||||||
tasks.push(cosmic::task::message(Message::Surface(
|
#[cfg(feature = "wayland")]
|
||||||
cosmic::surface::action::destroy_popup(popup_id),
|
if is_wayland() {
|
||||||
)));
|
tasks.push(cosmic::task::message(Message::Surface(
|
||||||
|
cosmic::surface::action::destroy_popup(_popup_id),
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all terminal context_menu state
|
// Clear all terminal context_menu state
|
||||||
|
|
@ -2835,18 +2843,26 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(menu_state) = menu_state {
|
if let Some(menu_state) = menu_state {
|
||||||
if let Some(position) = menu_state.position {
|
if let Some(_position) = menu_state.position {
|
||||||
|
let local_position = menu_state.local_position.unwrap_or(_position);
|
||||||
if let Some(tab_model) = self.pane_model.panes.get(pane) {
|
if let Some(tab_model) = self.pane_model.panes.get(pane) {
|
||||||
{
|
let entity = tab_model.active();
|
||||||
let entity = tab_model.active();
|
let link = menu_state.link.clone();
|
||||||
let link = menu_state.link.clone();
|
let popup_id = window::Id::unique();
|
||||||
let popup_id = window::Id::unique();
|
self.context_menu_popup = Some((
|
||||||
self.context_menu_popup =
|
popup_id,
|
||||||
Some((popup_id, pane, entity, link, widget::Id::unique()));
|
pane,
|
||||||
|
entity,
|
||||||
|
link,
|
||||||
|
widget::Id::unique(),
|
||||||
|
local_position,
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(feature = "wayland")]
|
||||||
|
if is_wayland() {
|
||||||
let main_window = self.core.main_window_id().unwrap();
|
let main_window = self.core.main_window_id().unwrap();
|
||||||
let pos_x = position.x as i32;
|
let pos_x = _position.x as i32;
|
||||||
let pos_y = position.y as i32;
|
let pos_y = _position.y as i32;
|
||||||
|
|
||||||
tasks.push(cosmic::task::message(Message::Surface(
|
tasks.push(cosmic::task::message(Message::Surface(
|
||||||
cosmic::surface::action::app_popup(move |_app: &mut Self| {
|
cosmic::surface::action::app_popup(move |_app: &mut Self| {
|
||||||
|
|
@ -3159,7 +3175,7 @@ impl Application for App {
|
||||||
return self.update_config();
|
return self.update_config();
|
||||||
}
|
}
|
||||||
Message::ContextMenuPopupClosed(id) => {
|
Message::ContextMenuPopupClosed(id) => {
|
||||||
if let Some((popup_id, _, _, _, _)) = &self.context_menu_popup {
|
if let Some((popup_id, _, _, _, _, _)) = &self.context_menu_popup {
|
||||||
if id == *popup_id {
|
if id == *popup_id {
|
||||||
self.context_menu_popup = None;
|
self.context_menu_popup = None;
|
||||||
}
|
}
|
||||||
|
|
@ -3272,7 +3288,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_close_requested(&self, id: window::Id) -> Option<Self::Message> {
|
fn on_close_requested(&self, id: window::Id) -> Option<Self::Message> {
|
||||||
if let Some((popup_id, _, _, _, _)) = &self.context_menu_popup {
|
if let Some((popup_id, _, _, _, _, _)) = &self.context_menu_popup {
|
||||||
if id == *popup_id {
|
if id == *popup_id {
|
||||||
return Some(Message::ContextMenuPopupClosed(id));
|
return Some(Message::ContextMenuPopupClosed(id));
|
||||||
}
|
}
|
||||||
|
|
@ -3281,7 +3297,8 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, window_id: window::Id) -> Element<'_, Message> {
|
fn view_window(&self, window_id: window::Id) -> Element<'_, Message> {
|
||||||
if let Some((popup_id, _pane, entity, ref link, ref autosize_id)) = self.context_menu_popup
|
if let Some((popup_id, _pane, entity, ref link, ref autosize_id, _)) =
|
||||||
|
self.context_menu_popup
|
||||||
{
|
{
|
||||||
if window_id == popup_id {
|
if window_id == popup_id {
|
||||||
return widget::autosize::autosize(
|
return widget::autosize::autosize(
|
||||||
|
|
@ -3365,7 +3382,42 @@ impl Application for App {
|
||||||
terminal_box = terminal_box.context_menu(cosmic::iced::Point::ORIGIN);
|
terminal_box = terminal_box.context_menu(cosmic::iced::Point::ORIGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tab_element: Element<'_, Message> = terminal_box.into();
|
let use_wayland_popup = {
|
||||||
|
#[cfg(feature = "wayland")]
|
||||||
|
{
|
||||||
|
is_wayland()
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "wayland"))]
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tab_element: Element<'_, Message> = if !use_wayland_popup {
|
||||||
|
// Fallback: render context menu as an inline popover
|
||||||
|
if let Some((_, popup_pane, popup_entity, ref link, _, point)) =
|
||||||
|
self.context_menu_popup
|
||||||
|
{
|
||||||
|
if pane == popup_pane {
|
||||||
|
let mut popover = widget::popover(terminal_box.context_menu(point));
|
||||||
|
popover = popover
|
||||||
|
.popup(menu::context_menu(
|
||||||
|
&self.config,
|
||||||
|
&self.key_binds,
|
||||||
|
popup_entity,
|
||||||
|
link.clone(),
|
||||||
|
))
|
||||||
|
.position(widget::popover::Position::Point(point));
|
||||||
|
popover.into()
|
||||||
|
} else {
|
||||||
|
terminal_box.into()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
terminal_box.into()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
terminal_box.into()
|
||||||
|
};
|
||||||
tab_column = tab_column.push(tab_element);
|
tab_column = tab_column.push(tab_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3519,3 +3571,11 @@ impl Application for App {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wayland")]
|
||||||
|
fn is_wayland() -> bool {
|
||||||
|
matches!(
|
||||||
|
cosmic::app::cosmic::windowing_system(),
|
||||||
|
Some(cosmic::app::cosmic::WindowingSystem::Wayland)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ static MENU_ID: LazyLock<cosmic::widget::Id> =
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MenuState {
|
pub struct MenuState {
|
||||||
pub position: Option<Point>,
|
pub position: Option<Point>,
|
||||||
|
pub local_position: Option<Point>,
|
||||||
pub link: Option<String>,
|
pub link: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1306,6 +1306,7 @@ where
|
||||||
);
|
);
|
||||||
shell.publish(on_context_menu(Some(MenuState {
|
shell.publish(on_context_menu(Some(MenuState {
|
||||||
position: Some(abs),
|
position: Some(abs),
|
||||||
|
local_position: Some(p),
|
||||||
link,
|
link,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue