xwayland: Handle _NET_ACTIVE_WINDOW client messages
Allow X11 clients to activate a window. This shares the logic with xdg-activation. It might make sense to handle the urgent hint on an X11 Window natively, but for now this just marks a workspace as urgent on activation in the same way xdg-activation does.
This commit is contained in:
parent
8fc7f0809f
commit
cf55b6c899
2 changed files with 139 additions and 114 deletions
|
|
@ -106,132 +106,145 @@ impl XdgActivationHandler for State {
|
||||||
let Some(context) = token_data.user_data.get::<ActivationContext>() else {
|
let Some(context) = token_data.user_data.get::<ActivationContext>() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut shell = self.common.shell.write();
|
|
||||||
|
|
||||||
match context {
|
match context {
|
||||||
ActivationContext::UrgentOnly => {
|
ActivationContext::UrgentOnly => {
|
||||||
|
let shell = self.common.shell.write();
|
||||||
if let Some((workspace, _output)) = shell.workspace_for_surface(&surface) {
|
if let Some((workspace, _output)) = shell.workspace_for_surface(&surface) {
|
||||||
let mut workspace_guard = self.common.workspace_state.update();
|
let mut workspace_guard = self.common.workspace_state.update();
|
||||||
workspace_guard.add_workspace_state(&workspace, WState::Urgent);
|
workspace_guard.add_workspace_state(&workspace, WState::Urgent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActivationContext::Workspace(_) => {
|
ActivationContext::Workspace(_) => {
|
||||||
let seat = shell.seats.last_active().clone();
|
self.activate_surface(
|
||||||
let current_output = seat.active_output();
|
&surface,
|
||||||
|
Some((ActivationKey::Wayland(surface.clone()), *context)),
|
||||||
if let Some(element) = shell.element_for_surface(&surface).cloned() {
|
);
|
||||||
if element.is_minimized() {
|
|
||||||
shell.unminimize_request(&surface, &seat, &self.common.event_loop_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some((element_output, element_workspace)) = shell
|
|
||||||
.space_for(&element)
|
|
||||||
.map(|w| (w.output.clone(), w.handle))
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let in_current_workspace =
|
|
||||||
element_workspace == shell.active_space(¤t_output).unwrap().handle;
|
|
||||||
|
|
||||||
if !in_current_workspace {
|
|
||||||
let Some(idx) = shell
|
|
||||||
.workspaces
|
|
||||||
.idx_for_handle(&element_output, &element_workspace)
|
|
||||||
else {
|
|
||||||
warn!("Couldn't determine idx for elements workspace?");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = shell.activate(
|
|
||||||
&element_output,
|
|
||||||
idx,
|
|
||||||
WorkspaceDelta::new_shortcut(),
|
|
||||||
&mut self.common.workspace_state.update(),
|
|
||||||
) {
|
|
||||||
warn!("Failed to activate the workspace: {err:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_workspace = shell.active_space_mut(¤t_output).unwrap();
|
|
||||||
current_workspace
|
|
||||||
.floating_layer
|
|
||||||
.space
|
|
||||||
.raise_element(&element, true);
|
|
||||||
if element.is_stack() {
|
|
||||||
if let Some((window, _)) = element.windows().find(|(window, _)| {
|
|
||||||
let mut found = false;
|
|
||||||
window.with_surfaces(|wl_surface, _| {
|
|
||||||
if wl_surface == &surface {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
found
|
|
||||||
}) {
|
|
||||||
element.set_active(&window);
|
|
||||||
} else {
|
|
||||||
warn!("Failed to find activated window in the stack");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if seat.get_keyboard().unwrap().current_focus() != Some(element.clone().into())
|
|
||||||
&& current_workspace.is_tiled(&surface)
|
|
||||||
{
|
|
||||||
for mapped in current_workspace
|
|
||||||
.mapped()
|
|
||||||
.filter(|m| m.maximized_state.lock().unwrap().is_some())
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_iter()
|
|
||||||
{
|
|
||||||
current_workspace.unmaximize_request(&mapped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::mem::drop(shell);
|
|
||||||
Shell::set_focus(
|
|
||||||
self,
|
|
||||||
Some(&KeyboardFocusTarget::Element(element.clone())),
|
|
||||||
&seat,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
} else if let Some((workspace, _)) = shell.workspace_for_surface(&surface) {
|
|
||||||
let current_workspace = shell.active_space(¤t_output).unwrap();
|
|
||||||
if workspace == current_workspace.handle {
|
|
||||||
let Some(target) = shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle(&workspace)
|
|
||||||
.unwrap()
|
|
||||||
.get_fullscreen()
|
|
||||||
.cloned()
|
|
||||||
.map(KeyboardFocusTarget::Fullscreen)
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::mem::drop(shell);
|
|
||||||
Shell::set_focus(self, Some(&target), &seat, None, false);
|
|
||||||
} else {
|
|
||||||
if let Some(surface) = shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle(&workspace)
|
|
||||||
.and_then(|w| w.get_fullscreen())
|
|
||||||
.cloned()
|
|
||||||
{
|
|
||||||
shell.append_focus_stack(surface, &seat)
|
|
||||||
}
|
|
||||||
let mut workspace_guard = self.common.workspace_state.update();
|
|
||||||
workspace_guard.add_workspace_state(&workspace, WState::Urgent);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shell
|
|
||||||
.pending_activations
|
|
||||||
.insert(ActivationKey::Wayland(surface), *context);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn activate_surface(
|
||||||
|
&mut self,
|
||||||
|
surface: &WlSurface,
|
||||||
|
pending_activation: Option<(ActivationKey, ActivationContext)>,
|
||||||
|
) {
|
||||||
|
let mut shell = self.common.shell.write();
|
||||||
|
|
||||||
|
let seat = shell.seats.last_active().clone();
|
||||||
|
let current_output = seat.active_output();
|
||||||
|
|
||||||
|
if let Some(element) = shell.element_for_surface(surface).cloned() {
|
||||||
|
if element.is_minimized() {
|
||||||
|
shell.unminimize_request(surface, &seat, &self.common.event_loop_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some((element_output, element_workspace)) = shell
|
||||||
|
.space_for(&element)
|
||||||
|
.map(|w| (w.output.clone(), w.handle))
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let in_current_workspace =
|
||||||
|
element_workspace == shell.active_space(¤t_output).unwrap().handle;
|
||||||
|
|
||||||
|
if !in_current_workspace {
|
||||||
|
let Some(idx) = shell
|
||||||
|
.workspaces
|
||||||
|
.idx_for_handle(&element_output, &element_workspace)
|
||||||
|
else {
|
||||||
|
warn!("Couldn't determine idx for elements workspace?");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = shell.activate(
|
||||||
|
&element_output,
|
||||||
|
idx,
|
||||||
|
WorkspaceDelta::new_shortcut(),
|
||||||
|
&mut self.common.workspace_state.update(),
|
||||||
|
) {
|
||||||
|
warn!("Failed to activate the workspace: {err:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_workspace = shell.active_space_mut(¤t_output).unwrap();
|
||||||
|
current_workspace
|
||||||
|
.floating_layer
|
||||||
|
.space
|
||||||
|
.raise_element(&element, true);
|
||||||
|
if element.is_stack() {
|
||||||
|
if let Some((window, _)) = element.windows().find(|(window, _)| {
|
||||||
|
let mut found = false;
|
||||||
|
window.with_surfaces(|wl_surface, _| {
|
||||||
|
if wl_surface == surface {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
found
|
||||||
|
}) {
|
||||||
|
element.set_active(&window);
|
||||||
|
} else {
|
||||||
|
warn!("Failed to find activated window in the stack");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if seat.get_keyboard().unwrap().current_focus() != Some(element.clone().into())
|
||||||
|
&& current_workspace.is_tiled(surface)
|
||||||
|
{
|
||||||
|
for mapped in current_workspace
|
||||||
|
.mapped()
|
||||||
|
.filter(|m| m.maximized_state.lock().unwrap().is_some())
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
|
current_workspace.unmaximize_request(&mapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mem::drop(shell);
|
||||||
|
Shell::set_focus(
|
||||||
|
self,
|
||||||
|
Some(&KeyboardFocusTarget::Element(element.clone())),
|
||||||
|
&seat,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
} else if let Some((workspace, _)) = shell.workspace_for_surface(&surface) {
|
||||||
|
let current_workspace = shell.active_space(¤t_output).unwrap();
|
||||||
|
if workspace == current_workspace.handle {
|
||||||
|
let Some(target) = shell
|
||||||
|
.workspaces
|
||||||
|
.space_for_handle(&workspace)
|
||||||
|
.unwrap()
|
||||||
|
.get_fullscreen()
|
||||||
|
.cloned()
|
||||||
|
.map(KeyboardFocusTarget::Fullscreen)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::mem::drop(shell);
|
||||||
|
Shell::set_focus(self, Some(&target), &seat, None, false);
|
||||||
|
} else {
|
||||||
|
if let Some(surface) = shell
|
||||||
|
.workspaces
|
||||||
|
.space_for_handle(&workspace)
|
||||||
|
.and_then(|w| w.get_fullscreen())
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
|
shell.append_focus_stack(surface, &seat)
|
||||||
|
}
|
||||||
|
let mut workspace_guard = self.common.workspace_state.update();
|
||||||
|
workspace_guard.add_workspace_state(&workspace, WState::Urgent);
|
||||||
|
}
|
||||||
|
} else if let Some((activation_key, context)) = pending_activation {
|
||||||
|
shell.pending_activations.insert(activation_key, context);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delegate_xdg_activation!(State);
|
delegate_xdg_activation!(State);
|
||||||
|
|
|
||||||
|
|
@ -1110,6 +1110,18 @@ impl XwmHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn active_window_request(
|
||||||
|
&mut self,
|
||||||
|
_xwm: XwmId,
|
||||||
|
window: X11Surface,
|
||||||
|
_timestamp: u32,
|
||||||
|
_currently_active_window: Option<X11Surface>,
|
||||||
|
) {
|
||||||
|
if let Some(surface) = window.wl_surface() {
|
||||||
|
self.activate_surface(&surface, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn send_selection(
|
fn send_selection(
|
||||||
&mut self,
|
&mut self,
|
||||||
_xwm: XwmId,
|
_xwm: XwmId,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue