xwayland: split window property loading
This commit is contained in:
parent
7531c8f791
commit
ea7251d6e0
3 changed files with 429 additions and 405 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
#![allow(clippy::await_holding_refcell_ref)] // all borrows are to data that is only used by this task
|
#![allow(clippy::await_holding_refcell_ref)] // all borrows are to data that is only used by this task
|
||||||
|
|
||||||
mod selection;
|
mod selection;
|
||||||
|
mod properties;
|
||||||
mod transfer;
|
mod transfer;
|
||||||
|
|
||||||
use selection::SelectionData;
|
use selection::SelectionData;
|
||||||
|
|
@ -9,7 +10,6 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
client::Client,
|
client::Client,
|
||||||
criteria::tlm::{TL_CHANGED_CLASS_INST, TL_CHANGED_ROLE},
|
|
||||||
ifs::{
|
ifs::{
|
||||||
data_transfer::{
|
data_transfer::{
|
||||||
DataOfferId, DataSourceId, DynDataOffer, DynDataSource, TransferLocation, TransferVtable,
|
DataOfferId, DataSourceId, DynDataOffer, DynDataSource, TransferLocation, TransferVtable,
|
||||||
|
|
@ -22,7 +22,7 @@ use {
|
||||||
wl_seat::{SeatId, WlSeatGlobal},
|
wl_seat::{SeatId, WlSeatGlobal},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
WlSurface,
|
WlSurface,
|
||||||
x_surface::xwindow::{XInputModel, Xwindow, XwindowData},
|
x_surface::xwindow::{Xwindow, XwindowData},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
|
|
@ -46,7 +46,7 @@ use {
|
||||||
ChangeProperty, ChangeWindowAttributes, ClientMessage, CompositeRedirectSubwindows,
|
ChangeProperty, ChangeWindowAttributes, ClientMessage, CompositeRedirectSubwindows,
|
||||||
ConfigureNotify, ConfigureRequest, ConfigureWindow, ConfigureWindowValues,
|
ConfigureNotify, ConfigureRequest, ConfigureWindow, ConfigureWindowValues,
|
||||||
ConvertSelection, CreateNotify, CreateWindow, CreateWindowValues, DestroyNotify,
|
ConvertSelection, CreateNotify, CreateWindow, CreateWindowValues, DestroyNotify,
|
||||||
Extension, FocusIn, GetAtomName, GetGeometry, InternAtom, KillClient, MapNotify,
|
Extension, FocusIn, GetGeometry, InternAtom, KillClient, MapNotify,
|
||||||
MapRequest, MapWindow, PropertyNotify, ResClientIdSpec, ResQueryClientIds,
|
MapRequest, MapWindow, PropertyNotify, ResClientIdSpec, ResQueryClientIds,
|
||||||
SelectSelectionInput, SelectionNotify, SelectionRequest, SetInputFocus,
|
SelectSelectionInput, SelectionNotify, SelectionRequest, SetInputFocus,
|
||||||
SetSelectionOwner, UnmapNotify, XfixesQueryVersion, XfixesSelectionNotify,
|
SetSelectionOwner, UnmapNotify, XfixesQueryVersion, XfixesSelectionNotify,
|
||||||
|
|
@ -56,14 +56,13 @@ use {
|
||||||
consts::{
|
consts::{
|
||||||
_NET_WM_STATE_ADD, _NET_WM_STATE_REMOVE, _NET_WM_STATE_TOGGLE, ATOM_ATOM,
|
_NET_WM_STATE_ADD, _NET_WM_STATE_REMOVE, _NET_WM_STATE_TOGGLE, ATOM_ATOM,
|
||||||
ATOM_NONE, ATOM_STRING, ATOM_WINDOW, ATOM_WM_CLASS, ATOM_WM_NAME,
|
ATOM_NONE, ATOM_STRING, ATOM_WINDOW, ATOM_WM_CLASS, ATOM_WM_NAME,
|
||||||
ATOM_WM_SIZE_HINTS, ATOM_WM_TRANSIENT_FOR, COMPOSITE_REDIRECT_MANUAL,
|
ATOM_WM_TRANSIENT_FOR, COMPOSITE_REDIRECT_MANUAL, CONFIG_WINDOW_HEIGHT,
|
||||||
CONFIG_WINDOW_HEIGHT, CONFIG_WINDOW_WIDTH, CONFIG_WINDOW_X, CONFIG_WINDOW_Y,
|
CONFIG_WINDOW_WIDTH, CONFIG_WINDOW_X, CONFIG_WINDOW_Y, EVENT_MASK_FOCUS_CHANGE,
|
||||||
EVENT_MASK_FOCUS_CHANGE, EVENT_MASK_PROPERTY_CHANGE,
|
EVENT_MASK_PROPERTY_CHANGE, EVENT_MASK_SUBSTRUCTURE_NOTIFY,
|
||||||
EVENT_MASK_SUBSTRUCTURE_NOTIFY, EVENT_MASK_SUBSTRUCTURE_REDIRECT,
|
EVENT_MASK_SUBSTRUCTURE_REDIRECT, ICCCM_WM_STATE_ICONIC, ICCCM_WM_STATE_NORMAL,
|
||||||
ICCCM_WM_HINT_INPUT, ICCCM_WM_STATE_ICONIC, ICCCM_WM_STATE_NORMAL,
|
ICCCM_WM_STATE_WITHDRAWN, INPUT_FOCUS_POINTER_ROOT, NOTIFY_DETAIL_POINTER,
|
||||||
ICCCM_WM_STATE_WITHDRAWN, INPUT_FOCUS_POINTER_ROOT, MWM_HINTS_DECORATIONS_FIELD,
|
NOTIFY_MODE_GRAB, NOTIFY_MODE_UNGRAB, PROP_MODE_REPLACE,
|
||||||
MWM_HINTS_FLAGS_FIELD, NOTIFY_DETAIL_POINTER, NOTIFY_MODE_GRAB, NOTIFY_MODE_UNGRAB,
|
RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID, SELECTION_CLIENT_CLOSE_MASK,
|
||||||
PROP_MODE_REPLACE, RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID, SELECTION_CLIENT_CLOSE_MASK,
|
|
||||||
SELECTION_WINDOW_DESTROY_MASK, SET_SELECTION_OWNER_MASK, STACK_MODE_ABOVE,
|
SELECTION_WINDOW_DESTROY_MASK, SET_SELECTION_OWNER_MASK, STACK_MODE_ABOVE,
|
||||||
STACK_MODE_BELOW, WINDOW_CLASS_INPUT_OUTPUT,
|
STACK_MODE_BELOW, WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
},
|
},
|
||||||
|
|
@ -71,7 +70,7 @@ use {
|
||||||
xwayland::{XWaylandError, XWaylandEvent},
|
xwayland::{XWaylandError, XWaylandEvent},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
bstr::{ByteSlice, ByteVec},
|
bstr::ByteSlice,
|
||||||
futures_util::{FutureExt, select},
|
futures_util::{FutureExt, select},
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -838,398 +837,6 @@ impl Wm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_input_model(&self, data: &Rc<XwindowData>) {
|
|
||||||
let has_wm_take_focus = data.info.protocols.contains(&self.atoms.WM_TAKE_FOCUS);
|
|
||||||
let accepts_input = data.info.icccm_hints.input.get();
|
|
||||||
let model = match (accepts_input, has_wm_take_focus) {
|
|
||||||
(false, false) => XInputModel::None,
|
|
||||||
(true, false) => XInputModel::Passive,
|
|
||||||
(true, true) => XInputModel::Local,
|
|
||||||
(false, true) => XInputModel::Global,
|
|
||||||
};
|
|
||||||
data.info.input_model.set(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_window_role(&self, data: &Rc<XwindowData>) {
|
|
||||||
let property_changed = || {
|
|
||||||
if let Some(window) = data.window.get() {
|
|
||||||
window.toplevel_data.property_changed(TL_CHANGED_ROLE);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut buf = vec![];
|
|
||||||
match self
|
|
||||||
.c
|
|
||||||
.get_property::<u8>(data.window_id, self.atoms.WM_WINDOW_ROLE, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(ty) if ty == ATOM_STRING => {}
|
|
||||||
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
|
|
||||||
Ok(ty) => {
|
|
||||||
self.unexpected_type(data.window_id, "WM_WINDOW_ROLE", ty)
|
|
||||||
.await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(XconError::PropertyUnavailable) => {
|
|
||||||
data.info.role.borrow_mut().take();
|
|
||||||
property_changed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve WM_WINDOW_ROLE property: {}",
|
|
||||||
ErrorFmt(e)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// log::info!("{} role {}", data.window_id, buf.as_bstr());
|
|
||||||
*data.info.role.borrow_mut() = Some(buf.into_string_lossy());
|
|
||||||
property_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_class(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
let property_changed = || {
|
|
||||||
if let Some(window) = data.window.get() {
|
|
||||||
let class = data.info.class.borrow();
|
|
||||||
for handle in window.toplevel_data.manager_handles.lock().values() {
|
|
||||||
handle.send_app_id(class.as_deref().unwrap_or_default());
|
|
||||||
handle.send_done();
|
|
||||||
}
|
|
||||||
window.toplevel_data.property_changed(TL_CHANGED_CLASS_INST);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match self
|
|
||||||
.c
|
|
||||||
.get_property::<u8>(data.window_id, ATOM_WM_CLASS, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(ty) if ty == ATOM_STRING => {}
|
|
||||||
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
|
|
||||||
Ok(ty) => {
|
|
||||||
self.unexpected_type(data.window_id, "WM_CLASS", ty).await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(XconError::PropertyUnavailable) => {
|
|
||||||
data.info.instance.borrow_mut().take();
|
|
||||||
data.info.class.borrow_mut().take();
|
|
||||||
property_changed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not retrieve WM_CLASS property: {}", ErrorFmt(e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut iter = buf.split(|c| *c == 0);
|
|
||||||
let mut map = || Some(iter.next().unwrap_or(&[]).to_str_lossy().into_owned());
|
|
||||||
*data.info.instance.borrow_mut() = map();
|
|
||||||
*data.info.class.borrow_mut() = map();
|
|
||||||
property_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_name2(&self, data: &Rc<XwindowData>, prop: u32, name: &str) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
match self
|
|
||||||
.c
|
|
||||||
.get_property::<u8>(data.window_id, prop, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(ty) if ty == ATOM_STRING && data.info.utf8_title.get() => return,
|
|
||||||
Ok(ty) if ty == ATOM_STRING => {}
|
|
||||||
Ok(ty) if ty == self.atoms.COMPOUND_TEXT => return, // used by java.
|
|
||||||
Ok(ty) if ty == self.atoms.UTF8_STRING => {
|
|
||||||
data.info.utf8_title.set(true);
|
|
||||||
}
|
|
||||||
Ok(ty) => {
|
|
||||||
self.unexpected_type(data.window_id, name, ty).await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(XconError::PropertyUnavailable) => return,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not retrieve {} property: {}", name, ErrorFmt(e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let title = buf.as_bstr().to_string();
|
|
||||||
if let Some(window) = data.window.get() {
|
|
||||||
window.toplevel_data.set_title(&title);
|
|
||||||
window.tl_title_changed();
|
|
||||||
}
|
|
||||||
*data.info.title.borrow_mut() = Some(title);
|
|
||||||
data.title_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn unexpected_type(&self, window: u32, prop: &str, ty: u32) {
|
|
||||||
let mut ty_name = "unknown".as_bytes().as_bstr();
|
|
||||||
let res = self.c.call(&GetAtomName { atom: ty }).await;
|
|
||||||
if let Ok(res) = &res {
|
|
||||||
ty_name = res.get().name;
|
|
||||||
}
|
|
||||||
log::error!(
|
|
||||||
"Property {} of window {} has unexpected type {} ({})",
|
|
||||||
prop,
|
|
||||||
window,
|
|
||||||
ty_name,
|
|
||||||
ty
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_name(&self, data: &Rc<XwindowData>) {
|
|
||||||
self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME")
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_net_wm_name(&self, data: &Rc<XwindowData>) {
|
|
||||||
self.load_window_wm_name2(data, self.atoms._NET_WM_NAME, "_NET_WM_NAME")
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_transient_for(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(data.window_id, ATOM_WM_TRANSIENT_FOR, ATOM_WINDOW, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve WM_TRANSIENT_FOR property: {}",
|
|
||||||
ErrorFmt(e)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(old) = data.parent.take() {
|
|
||||||
old.children.remove(&data.window_id);
|
|
||||||
}
|
|
||||||
if let Some(w) = buf.first()
|
|
||||||
&& let Some(w) = self.windows.get(w)
|
|
||||||
{
|
|
||||||
if data.is_ancestor_of(w.clone()) {
|
|
||||||
log::error!("Cannot set WM_TRANSIENT_FOR because it would create a cycle");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
w.children.set(data.window_id, data.clone());
|
|
||||||
data.parent.set(Some(w.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_protocols(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(data.window_id, self.atoms.WM_PROTOCOLS, ATOM_ATOM, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!("Could not retrieve WM_PROTOCOLS property: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data.info.protocols.clear();
|
|
||||||
data.info
|
|
||||||
.protocols
|
|
||||||
.lock()
|
|
||||||
.extend(buf.iter().copied().map(|v| (v, ())));
|
|
||||||
self.compute_input_model(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_hints(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(data.window_id, self.atoms.WM_HINTS, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!("Could not retrieve WM_HINTS property: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
data.info.icccm_hints.input.set(true);
|
|
||||||
self.compute_input_model(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut values = [0; 9];
|
|
||||||
let len = values.len().min(buf.len());
|
|
||||||
values[..len].copy_from_slice(&buf[..len]);
|
|
||||||
data.info.icccm_hints.flags.set(values[0] as i32);
|
|
||||||
data.info.icccm_hints.input.set(values[1] != 0);
|
|
||||||
data.info.icccm_hints.initial_state.set(values[2] as i32);
|
|
||||||
data.info.icccm_hints.icon_pixmap.set(values[3]);
|
|
||||||
data.info.icccm_hints.icon_window.set(values[4]);
|
|
||||||
data.info.icccm_hints.icon_x.set(values[5] as i32);
|
|
||||||
data.info.icccm_hints.icon_y.set(values[6] as i32);
|
|
||||||
data.info.icccm_hints.icon_mask.set(values[7]);
|
|
||||||
data.info.icccm_hints.window_group.set(values[8]);
|
|
||||||
if data
|
|
||||||
.info
|
|
||||||
.icccm_hints
|
|
||||||
.flags
|
|
||||||
.get()
|
|
||||||
.not_contains(ICCCM_WM_HINT_INPUT)
|
|
||||||
{
|
|
||||||
data.info.icccm_hints.input.set(true);
|
|
||||||
}
|
|
||||||
self.compute_input_model(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_wm_normal_hints(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(
|
|
||||||
data.window_id,
|
|
||||||
self.atoms.WM_NORMAL_HINTS,
|
|
||||||
ATOM_WM_SIZE_HINTS,
|
|
||||||
&mut buf,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve WM_NORMAL_HINTS property: {}",
|
|
||||||
ErrorFmt(e)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut values = [0; 18];
|
|
||||||
let len = values.len().min(buf.len());
|
|
||||||
values[..len].copy_from_slice(&buf[..len]);
|
|
||||||
data.info.normal_hints.flags.set(values[0]);
|
|
||||||
data.info.normal_hints.x.set(values[1] as i32);
|
|
||||||
data.info.normal_hints.y.set(values[2] as i32);
|
|
||||||
data.info.normal_hints.width.set(values[3] as i32);
|
|
||||||
data.info.normal_hints.height.set(values[4] as i32);
|
|
||||||
data.info.normal_hints.min_width.set(values[5] as i32);
|
|
||||||
data.info.normal_hints.min_height.set(values[6] as i32);
|
|
||||||
data.info.normal_hints.max_width.set(values[7] as i32);
|
|
||||||
data.info.normal_hints.max_height.set(values[8] as i32);
|
|
||||||
data.info.normal_hints.width_inc.set(values[9] as i32);
|
|
||||||
data.info.normal_hints.height_inc.set(values[10] as i32);
|
|
||||||
data.info.normal_hints.min_aspect_num.set(values[11] as i32);
|
|
||||||
data.info.normal_hints.min_aspect_den.set(values[12] as i32);
|
|
||||||
data.info.normal_hints.max_aspect_num.set(values[13] as i32);
|
|
||||||
data.info.normal_hints.max_aspect_den.set(values[14] as i32);
|
|
||||||
data.info.normal_hints.base_width.set(values[15] as i32);
|
|
||||||
data.info.normal_hints.base_height.set(values[16] as i32);
|
|
||||||
data.info.normal_hints.win_gravity.set(values[17]);
|
|
||||||
self.update_wants_floating(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_motif_wm_hints(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(data.window_id, self.atoms._MOTIF_WM_HINTS, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve _MOTIF_WM_HINTS property: {}",
|
|
||||||
ErrorFmt(e)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut values = [0; 5];
|
|
||||||
let len = values.len().min(buf.len());
|
|
||||||
values[..len].copy_from_slice(&buf[..len]);
|
|
||||||
data.info
|
|
||||||
.motif_hints
|
|
||||||
.flags
|
|
||||||
.set(values[MWM_HINTS_FLAGS_FIELD]);
|
|
||||||
data.info
|
|
||||||
.motif_hints
|
|
||||||
.decorations
|
|
||||||
.set(values[MWM_HINTS_DECORATIONS_FIELD]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_net_startup_id(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
match self
|
|
||||||
.c
|
|
||||||
.get_property::<u8>(data.window_id, self.atoms._NET_STARTUP_ID, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(ty) if ty == ATOM_STRING => {}
|
|
||||||
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
|
|
||||||
Ok(ty) => {
|
|
||||||
self.unexpected_type(data.window_id, "_NET_STARTUP_ID", ty)
|
|
||||||
.await;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(XconError::PropertyUnavailable) => return,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve _NET_STARTUP_ID property: {}",
|
|
||||||
ErrorFmt(e)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*data.info.startup_id.borrow_mut() = Some(buf.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_net_wm_state(&self, data: &Rc<XwindowData>) {
|
|
||||||
data.info.fullscreen.set(false);
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(data.window_id, self.atoms._NET_WM_STATE, 0, &mut buf)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!("Could not retrieve _NET_WM_STATE property: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for prop in buf {
|
|
||||||
if prop == self.atoms._NET_WM_STATE_MODAL {
|
|
||||||
data.info.modal.set(true);
|
|
||||||
self.update_wants_floating(data);
|
|
||||||
} else if prop == self.atoms._NET_WM_STATE_FULLSCREEN {
|
|
||||||
data.info.fullscreen.set(true);
|
|
||||||
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_VERT {
|
|
||||||
data.info.maximized_vert.set(true);
|
|
||||||
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_HORZ {
|
|
||||||
data.info.maximized_horz.set(true);
|
|
||||||
} else if prop == self.atoms._NET_WM_STATE_HIDDEN {
|
|
||||||
data.info.minimized.set(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_window_net_wm_window_type(&self, data: &Rc<XwindowData>) {
|
|
||||||
let mut buf = vec![];
|
|
||||||
if let Err(e) = self
|
|
||||||
.c
|
|
||||||
.get_property::<u32>(
|
|
||||||
data.window_id,
|
|
||||||
self.atoms._NET_WM_WINDOW_TYPE,
|
|
||||||
ATOM_ATOM,
|
|
||||||
&mut buf,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if not_matches!(e, XconError::PropertyUnavailable) {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve _NET_WM_WINDOW_TYPE property: {}",
|
|
||||||
ErrorFmt(e)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data.info
|
|
||||||
.never_focus
|
|
||||||
.set(buf.iter().any(|t| self.never_focus.contains(t)));
|
|
||||||
data.info.window_types.clear();
|
|
||||||
data.info
|
|
||||||
.window_types
|
|
||||||
.lock()
|
|
||||||
.extend(buf.iter().copied().map(|v| (v, ())));
|
|
||||||
self.update_wants_floating(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_window(&mut self, data: &Rc<XwindowData>, surface: Rc<WlSurface>) {
|
async fn create_window(&mut self, data: &Rc<XwindowData>, surface: Rc<WlSurface>) {
|
||||||
if data.window.is_some() {
|
if data.window.is_some() {
|
||||||
log::error!("The xwindow has already been constructed");
|
log::error!("The xwindow has already been constructed");
|
||||||
|
|
|
||||||
413
src/xwayland/xwm/properties.rs
Normal file
413
src/xwayland/xwm/properties.rs
Normal file
|
|
@ -0,0 +1,413 @@
|
||||||
|
use {
|
||||||
|
super::Wm,
|
||||||
|
crate::{
|
||||||
|
criteria::tlm::{TL_CHANGED_CLASS_INST, TL_CHANGED_ROLE},
|
||||||
|
ifs::wl_surface::x_surface::xwindow::{XInputModel, XwindowData},
|
||||||
|
tree::ToplevelNode,
|
||||||
|
utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt},
|
||||||
|
wire_xcon::GetAtomName,
|
||||||
|
xcon::{
|
||||||
|
XconError,
|
||||||
|
consts::{
|
||||||
|
ATOM_ATOM, ATOM_STRING, ATOM_WINDOW, ATOM_WM_CLASS, ATOM_WM_NAME,
|
||||||
|
ATOM_WM_SIZE_HINTS, ATOM_WM_TRANSIENT_FOR, ICCCM_WM_HINT_INPUT,
|
||||||
|
MWM_HINTS_DECORATIONS_FIELD, MWM_HINTS_FLAGS_FIELD,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bstr::{ByteSlice, ByteVec},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Wm {
|
||||||
|
pub(super) fn compute_input_model(&self, data: &Rc<XwindowData>) {
|
||||||
|
let has_wm_take_focus = data.info.protocols.contains(&self.atoms.WM_TAKE_FOCUS);
|
||||||
|
let accepts_input = data.info.icccm_hints.input.get();
|
||||||
|
let model = match (accepts_input, has_wm_take_focus) {
|
||||||
|
(false, false) => XInputModel::None,
|
||||||
|
(true, false) => XInputModel::Passive,
|
||||||
|
(true, true) => XInputModel::Local,
|
||||||
|
(false, true) => XInputModel::Global,
|
||||||
|
};
|
||||||
|
data.info.input_model.set(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_window_role(&self, data: &Rc<XwindowData>) {
|
||||||
|
let property_changed = || {
|
||||||
|
if let Some(window) = data.window.get() {
|
||||||
|
window.toplevel_data.property_changed(TL_CHANGED_ROLE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut buf = vec![];
|
||||||
|
match self
|
||||||
|
.c
|
||||||
|
.get_property::<u8>(data.window_id, self.atoms.WM_WINDOW_ROLE, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(ty) if ty == ATOM_STRING => {}
|
||||||
|
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
|
||||||
|
Ok(ty) => {
|
||||||
|
self.unexpected_type(data.window_id, "WM_WINDOW_ROLE", ty)
|
||||||
|
.await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(XconError::PropertyUnavailable) => {
|
||||||
|
data.info.role.borrow_mut().take();
|
||||||
|
property_changed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve WM_WINDOW_ROLE property: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*data.info.role.borrow_mut() = Some(buf.into_string_lossy());
|
||||||
|
property_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_class(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
let property_changed = || {
|
||||||
|
if let Some(window) = data.window.get() {
|
||||||
|
let class = data.info.class.borrow();
|
||||||
|
for handle in window.toplevel_data.manager_handles.lock().values() {
|
||||||
|
handle.send_app_id(class.as_deref().unwrap_or_default());
|
||||||
|
handle.send_done();
|
||||||
|
}
|
||||||
|
window.toplevel_data.property_changed(TL_CHANGED_CLASS_INST);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match self
|
||||||
|
.c
|
||||||
|
.get_property::<u8>(data.window_id, ATOM_WM_CLASS, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(ty) if ty == ATOM_STRING => {}
|
||||||
|
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
|
||||||
|
Ok(ty) => {
|
||||||
|
self.unexpected_type(data.window_id, "WM_CLASS", ty).await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(XconError::PropertyUnavailable) => {
|
||||||
|
data.info.instance.borrow_mut().take();
|
||||||
|
data.info.class.borrow_mut().take();
|
||||||
|
property_changed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not retrieve WM_CLASS property: {}", ErrorFmt(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut iter = buf.split(|c| *c == 0);
|
||||||
|
let mut map = || Some(iter.next().unwrap_or(&[]).to_str_lossy().into_owned());
|
||||||
|
*data.info.instance.borrow_mut() = map();
|
||||||
|
*data.info.class.borrow_mut() = map();
|
||||||
|
property_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn load_window_wm_name2(&self, data: &Rc<XwindowData>, prop: u32, name: &str) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
match self
|
||||||
|
.c
|
||||||
|
.get_property::<u8>(data.window_id, prop, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(ty) if ty == ATOM_STRING && data.info.utf8_title.get() => return,
|
||||||
|
Ok(ty) if ty == ATOM_STRING => {}
|
||||||
|
Ok(ty) if ty == self.atoms.COMPOUND_TEXT => return,
|
||||||
|
Ok(ty) if ty == self.atoms.UTF8_STRING => {
|
||||||
|
data.info.utf8_title.set(true);
|
||||||
|
}
|
||||||
|
Ok(ty) => {
|
||||||
|
self.unexpected_type(data.window_id, name, ty).await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(XconError::PropertyUnavailable) => return,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not retrieve {} property: {}", name, ErrorFmt(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let title = buf.as_bstr().to_string();
|
||||||
|
if let Some(window) = data.window.get() {
|
||||||
|
window.toplevel_data.set_title(&title);
|
||||||
|
window.tl_title_changed();
|
||||||
|
}
|
||||||
|
*data.info.title.borrow_mut() = Some(title);
|
||||||
|
data.title_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unexpected_type(&self, window: u32, prop: &str, ty: u32) {
|
||||||
|
let mut ty_name = "unknown".as_bytes().as_bstr();
|
||||||
|
let res = self.c.call(&GetAtomName { atom: ty }).await;
|
||||||
|
if let Ok(res) = &res {
|
||||||
|
ty_name = res.get().name;
|
||||||
|
}
|
||||||
|
log::error!(
|
||||||
|
"Property {} of window {} has unexpected type {} ({})",
|
||||||
|
prop,
|
||||||
|
window,
|
||||||
|
ty_name,
|
||||||
|
ty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_name(&self, data: &Rc<XwindowData>) {
|
||||||
|
self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME")
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_net_wm_name(&self, data: &Rc<XwindowData>) {
|
||||||
|
self.load_window_wm_name2(data, self.atoms._NET_WM_NAME, "_NET_WM_NAME")
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_transient_for(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(data.window_id, ATOM_WM_TRANSIENT_FOR, ATOM_WINDOW, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve WM_TRANSIENT_FOR property: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(old) = data.parent.take() {
|
||||||
|
old.children.remove(&data.window_id);
|
||||||
|
}
|
||||||
|
if let Some(w) = buf.first()
|
||||||
|
&& let Some(w) = self.windows.get(w)
|
||||||
|
{
|
||||||
|
if data.is_ancestor_of(w.clone()) {
|
||||||
|
log::error!("Cannot set WM_TRANSIENT_FOR because it would create a cycle");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w.children.set(data.window_id, data.clone());
|
||||||
|
data.parent.set(Some(w.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_protocols(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(data.window_id, self.atoms.WM_PROTOCOLS, ATOM_ATOM, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!("Could not retrieve WM_PROTOCOLS property: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.info.protocols.clear();
|
||||||
|
data.info
|
||||||
|
.protocols
|
||||||
|
.lock()
|
||||||
|
.extend(buf.iter().copied().map(|v| (v, ())));
|
||||||
|
self.compute_input_model(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_hints(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(data.window_id, self.atoms.WM_HINTS, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!("Could not retrieve WM_HINTS property: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
data.info.icccm_hints.input.set(true);
|
||||||
|
self.compute_input_model(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut values = [0; 9];
|
||||||
|
let len = values.len().min(buf.len());
|
||||||
|
values[..len].copy_from_slice(&buf[..len]);
|
||||||
|
data.info.icccm_hints.flags.set(values[0] as i32);
|
||||||
|
data.info.icccm_hints.input.set(values[1] != 0);
|
||||||
|
data.info.icccm_hints.initial_state.set(values[2] as i32);
|
||||||
|
data.info.icccm_hints.icon_pixmap.set(values[3]);
|
||||||
|
data.info.icccm_hints.icon_window.set(values[4]);
|
||||||
|
data.info.icccm_hints.icon_x.set(values[5] as i32);
|
||||||
|
data.info.icccm_hints.icon_y.set(values[6] as i32);
|
||||||
|
data.info.icccm_hints.icon_mask.set(values[7]);
|
||||||
|
data.info.icccm_hints.window_group.set(values[8]);
|
||||||
|
if data
|
||||||
|
.info
|
||||||
|
.icccm_hints
|
||||||
|
.flags
|
||||||
|
.get()
|
||||||
|
.not_contains(ICCCM_WM_HINT_INPUT)
|
||||||
|
{
|
||||||
|
data.info.icccm_hints.input.set(true);
|
||||||
|
}
|
||||||
|
self.compute_input_model(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_wm_normal_hints(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(
|
||||||
|
data.window_id,
|
||||||
|
self.atoms.WM_NORMAL_HINTS,
|
||||||
|
ATOM_WM_SIZE_HINTS,
|
||||||
|
&mut buf,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve WM_NORMAL_HINTS property: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut values = [0; 18];
|
||||||
|
let len = values.len().min(buf.len());
|
||||||
|
values[..len].copy_from_slice(&buf[..len]);
|
||||||
|
data.info.normal_hints.flags.set(values[0]);
|
||||||
|
data.info.normal_hints.x.set(values[1] as i32);
|
||||||
|
data.info.normal_hints.y.set(values[2] as i32);
|
||||||
|
data.info.normal_hints.width.set(values[3] as i32);
|
||||||
|
data.info.normal_hints.height.set(values[4] as i32);
|
||||||
|
data.info.normal_hints.min_width.set(values[5] as i32);
|
||||||
|
data.info.normal_hints.min_height.set(values[6] as i32);
|
||||||
|
data.info.normal_hints.max_width.set(values[7] as i32);
|
||||||
|
data.info.normal_hints.max_height.set(values[8] as i32);
|
||||||
|
data.info.normal_hints.width_inc.set(values[9] as i32);
|
||||||
|
data.info.normal_hints.height_inc.set(values[10] as i32);
|
||||||
|
data.info.normal_hints.min_aspect_num.set(values[11] as i32);
|
||||||
|
data.info.normal_hints.min_aspect_den.set(values[12] as i32);
|
||||||
|
data.info.normal_hints.max_aspect_num.set(values[13] as i32);
|
||||||
|
data.info.normal_hints.max_aspect_den.set(values[14] as i32);
|
||||||
|
data.info.normal_hints.base_width.set(values[15] as i32);
|
||||||
|
data.info.normal_hints.base_height.set(values[16] as i32);
|
||||||
|
data.info.normal_hints.win_gravity.set(values[17]);
|
||||||
|
self.update_wants_floating(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_motif_wm_hints(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(data.window_id, self.atoms._MOTIF_WM_HINTS, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve _MOTIF_WM_HINTS property: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut values = [0; 5];
|
||||||
|
let len = values.len().min(buf.len());
|
||||||
|
values[..len].copy_from_slice(&buf[..len]);
|
||||||
|
data.info
|
||||||
|
.motif_hints
|
||||||
|
.flags
|
||||||
|
.set(values[MWM_HINTS_FLAGS_FIELD]);
|
||||||
|
data.info
|
||||||
|
.motif_hints
|
||||||
|
.decorations
|
||||||
|
.set(values[MWM_HINTS_DECORATIONS_FIELD]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_net_startup_id(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
match self
|
||||||
|
.c
|
||||||
|
.get_property::<u8>(data.window_id, self.atoms._NET_STARTUP_ID, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(ty) if ty == ATOM_STRING => {}
|
||||||
|
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
|
||||||
|
Ok(ty) => {
|
||||||
|
self.unexpected_type(data.window_id, "_NET_STARTUP_ID", ty)
|
||||||
|
.await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(XconError::PropertyUnavailable) => return,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve _NET_STARTUP_ID property: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*data.info.startup_id.borrow_mut() = Some(buf.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_net_wm_state(&self, data: &Rc<XwindowData>) {
|
||||||
|
data.info.fullscreen.set(false);
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(data.window_id, self.atoms._NET_WM_STATE, 0, &mut buf)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!("Could not retrieve _NET_WM_STATE property: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for prop in buf {
|
||||||
|
if prop == self.atoms._NET_WM_STATE_MODAL {
|
||||||
|
data.info.modal.set(true);
|
||||||
|
self.update_wants_floating(data);
|
||||||
|
} else if prop == self.atoms._NET_WM_STATE_FULLSCREEN {
|
||||||
|
data.info.fullscreen.set(true);
|
||||||
|
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_VERT {
|
||||||
|
data.info.maximized_vert.set(true);
|
||||||
|
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_HORZ {
|
||||||
|
data.info.maximized_horz.set(true);
|
||||||
|
} else if prop == self.atoms._NET_WM_STATE_HIDDEN {
|
||||||
|
data.info.minimized.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn load_window_net_wm_window_type(&self, data: &Rc<XwindowData>) {
|
||||||
|
let mut buf = vec![];
|
||||||
|
if let Err(e) = self
|
||||||
|
.c
|
||||||
|
.get_property::<u32>(
|
||||||
|
data.window_id,
|
||||||
|
self.atoms._NET_WM_WINDOW_TYPE,
|
||||||
|
ATOM_ATOM,
|
||||||
|
&mut buf,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
if not_matches!(e, XconError::PropertyUnavailable) {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve _NET_WM_WINDOW_TYPE property: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data.info
|
||||||
|
.never_focus
|
||||||
|
.set(buf.iter().any(|t| self.never_focus.contains(t)));
|
||||||
|
data.info.window_types.clear();
|
||||||
|
data.info
|
||||||
|
.window_types
|
||||||
|
.lock()
|
||||||
|
.extend(buf.iter().copied().map(|v| (v, ())));
|
||||||
|
self.update_wants_floating(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
use {super::*, super::transfer::{WaylandToXTransfer, XToWaylandTransfer}};
|
use {
|
||||||
|
super::*,
|
||||||
|
super::transfer::{WaylandToXTransfer, XToWaylandTransfer},
|
||||||
|
crate::wire_xcon::GetAtomName,
|
||||||
|
};
|
||||||
|
|
||||||
pub(super) struct EnhancedOffer {
|
pub(super) struct EnhancedOffer {
|
||||||
offer: Rc<XDataOffer>,
|
offer: Rc<XDataOffer>,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue