i3-companion: try to move windows in the same workspace as similar ones

This commit is contained in:
Vincent Bernat 2021-07-16 19:53:12 +02:00
parent 4e21366d7a
commit 84a535bb85

View file

@ -347,52 +347,67 @@ async def worksplace_exclusive(i3, event):
with an exclusive app.""" with an exclusive app."""
w = event.container w = event.container
def can_intrude(w): def partof(w, apps):
"""Can this new window intrude any workspace?""" """Provided window is part of the provided apps."""
if w.floating in {"auto_on", "user_on"}: names = {
return True
if w.ipc_data["window_type"] not in {"normal", "splash", "unknown"}:
return True
if w.sticky:
return True
ids = {
s is not None and s.lower() or None s is not None and s.lower() or None
for s in {w.name, w.window_class, w.window_instance} for s in {w.name, w.window_class, w.window_instance}
} }
if ids.intersection(intrusive_apps): return bool(names.intersection(apps))
return True
# Can the new window just intrude? # Can the current window intrude the workspace?
if can_intrude(w): if (
w.floating in {"auto_on", "user_on"}
or w.ipc_data["window_type"] not in {"normal", "splash", "unknown"}
or w.sticky
or partof(w, intrusive_apps)
):
logger.debug("window %s can intrude", w.name) logger.debug("window %s can intrude", w.name)
return return
# Get the workspace. From an event, w.workspace() is None, so
# search it in the tree.
tree = await i3.get_tree() tree = await i3.get_tree()
workspace = next(
(ow.workspace() for ow in tree.leaves() if w.id == ow.id), None # Get the window workspace. From an event, w.workspace() is None,
# so search it in the tree.
current_workspace = next(
(ow.workspace().num for ow in tree.leaves() if w.id == ow.id), None
) )
if not workspace: if not current_workspace:
logger.info(f"cannot get workspace for {w.window_class}")
return return
# Does the target workspace contains an exclusive app (not using # Get the list of workspaces with an exclusive app, excluding the
# the same class). # current window and windows of the same class.
ids = { exclusive_workspaces = {
s is not None and s.lower() or None ow.workspace().num
for ow in workspace.leaves() for ow in tree.leaves()
for s in {ow.name, ow.window_class, ow.window_instance} if w.id != ow.id
if w.id != ow.id and w.window_class != ow.window_class and (w.window_class or object()) != ow.window_class
and partof(ow, exclusive_apps)
} }
exclusives = ids.intersection(exclusive_apps)
if not exclusives: # If current one is OK, don't move
logger.debug("no exclusive app, %s can go there", w.name) if current_workspace not in exclusive_workspaces:
logger.debug("no exclusive app, %s can go there", w.window_class)
return return
# Create a new workspace and move the window here # Are there other workspaces with the same app but no exclusive apps?
candidate_workspaces = {
ow.workspace().num
for ow in tree.leaves()
if w.id != ow.id and (w.window_class or object()) == ow.window_class
}
candidate_workspaces -= exclusive_workspaces
if candidate_workspaces:
# Use one of the candidates
num = next(iter(candidate_workspaces))
else:
# Create a new workspace
num = await _new_workspace(i3) num = await _new_workspace(i3)
logger.info(f"move window {w.window_class} to workspace {num}") logger.info(f"move window {w.window_class} to workspace {num}")
await w.command(f'move container to workspace number "{num}"') await w.command(f'move container to workspace number "{num}", focus')
@on(CommandEvent("quake-console")) @on(CommandEvent("quake-console"))