Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implement sticky floating windows #2

Open
nikitabobko opened this issue Oct 14, 2023 · 20 comments
Open

Feature: Implement sticky floating windows #2

nikitabobko opened this issue Oct 14, 2023 · 20 comments
Labels
feature-proposal A well defined feature proposal

Comments

@nikitabobko
Copy link
Owner

nikitabobko commented Oct 14, 2023

https://i3wm.org/docs/userguide.html#_sticky_floating_windows

  • Implement sticky floating windows
  • Implement sticky sidebar windows (feature interaction with: flatten-workspace-tree, close-all-windows-but-current)

Note to myself: review usages of visualWorkspace

@AlJohri
Copy link

AlJohri commented Jan 24, 2024

Is it possible to have sticky non-floating windows? SImilar to this request: koekeishiya/yabai#1843

I'd like to have a constant window on my screen as I flip through workspaces.

@nikitabobko
Copy link
Owner Author

nikitabobko commented Jan 25, 2024

"sticky sidebar" windows bring some challenges

  • What if users want to have several sticky sidebar windows
  • What should happen if a sticky sidebar window is moved with the mouse?
    • Should it become a regular tiling window?
    • Or should it remain sticky sidebar?
  • Should "sticky sidebar" windows be a per-monitor thing?
    • If the answer is yes, how users are supposed to move sticky sidebar window between monitors?
      • What should happen if users move a window to a monitor where another sticky sidebar windows is already presented?

But in general, I like the suggestion, I always wanted to have sticky non-floating windows in i3

@nikitabobko
Copy link
Owner Author

Maybe we are better off with a feature like "virtual monitors". That way you could place two virtual monitors on your physical monitor. You could cycle workspaces only on one of those virtual monitors

@nasyxx
Copy link

nasyxx commented Mar 7, 2024

Is there any update on this? I have some widget windows; it would be great if we could keep them on all workspaces.

@tngafwlehmann
Copy link

tngafwlehmann commented Apr 10, 2024

Maybe we are better off with a feature like "virtual monitors". That way you could place two virtual monitors on your physical monitor. You could cycle workspaces only on one of those virtual monitors

That's indeed a great thing to have. For i3 I typically use xrandr to split up a 5120x? physical device into three virtual monitors, the latter of which can then be used for workspace assignments.

But this does not necessarily solve the issue for floating (possibly workspace-independent) windows (assuming a certain preference for floating Zoom/Teams/etc. because it's easier to re-arrange during meetings). So I'd vote for both :)

@TC-MO
Copy link

TC-MO commented Sep 19, 2024

Has this ever been implemented? I'm looking for a way to keep FF PiP window in the same position when moving workspaces

@farzadmf
Copy link

For now, I'm manually doing this when I switch workspaces:

  • Before I switch; I search to see if there are any PIP windows
  • I focus that window and move it to the target workspace (too bad aerospace doesn't let me do move-node-to-workspace --window-id <window-id> <target-ws> ... so sad 😔 )
  • Then, I switch to the target workspace.

I must say, it's a very weird and terrible experience, but at least the PIP window is "sticky"! 😐

@nikitabobko nikitabobko added the feature-proposal A well defined feature proposal label Sep 20, 2024
@gservat
Copy link

gservat commented Sep 26, 2024

Would be super neat to keep a Zoom floating window as sticky so I can see whats going on in a meeting while I cycle through workspaces.

@bitskc
Copy link

bitskc commented Oct 11, 2024

I'm definitely in need of this feature! Hope it comes soon!

@PaRr0tBoY
Copy link

Can we extend the functionality of exec-on-workspace-change,force specific windows to move-node-to-{{currently focused workspace}}?

@andsnpl
Copy link

andsnpl commented Oct 20, 2024

I thought this would be possible to jury-rig for at least one window using exec-on-workspace-change, but I'm not having much success. My attempt, in case anyone can make it work:

exec-on-workspace-change = ['/bin/bash', '-c',
  'WIN=$(aerospace list-windows --all | grep "<Window Title>" | cut -d" " -f1); [ -n "$WIN" ] && aerospace move-node-to-workspace --window-id="$WIN" "$AEROSPACE_FOCUSED_WORKSPACE"'
]

@gservat
Copy link

gservat commented Oct 20, 2024

@andsnpl: I think the issue with yours is the = after --window-id. This works:

exec-on-workspace-change = ['/bin/bash', '-c',
  'WIN=$(aerospace list-windows --all | grep "<Window Title>" | cut -d" " -f1); [ -n "$WIN" ] && aerospace move-node-to-workspace --window-id "$WIN" "$AEROSPACE_FOCUSED_WORKSPACE"'
]

However, it seemed to move the window to the focused workspace but it lost focus so it would be behind my other windows. I tried giving it focus as part of exec-on-workspace-change (see below), which kinda works (moves the window and gives it focus), but it's not really useable for my needs as clicking on any other window will send it to the back:

exec-on-workspace-change = ['/bin/bash', '-c',
  'WIN=$(aerospace list-windows --all | grep "<Window Title>" | cut -d" " -f1); [ -n "$WIN" ] && aerospace move-node-to-workspace --window-id "$WIN" "$AEROSPACE_FOCUSED_WORKSPACE" && aerospace focus --window-id "$WIN"'
]

@andsnpl
Copy link

andsnpl commented Oct 21, 2024

Edit: my bad. aerospace command was not in PATH for bash. It looks like I needed to run bash with --login to pick up the path through /etc/profile. Now I'm just curious why this wasn't an issue for you...

Thanks for the feedback @gservat. It still doesn't work for me. I tried echoing the winId to a file:

exec-on-workspace-change = ['/bin/bash', '-c',
  # 'WIN=$(aerospace list-windows --all | grep "<Window Title>" | cut -d" " -f1); [ -n "$WIN" ] && aerospace move-node-to-workspace --window-id "$WIN" "$AEROSPACE_FOCUSED_WORKSPACE"'
  'WIN=$(aerospace list-windows --all | grep "<Window Title>" | cut -d" " -f1); echo "$WIN -> $AEROSPACE_FOCUSED_WORKSPACE" > "$HOME/Desktop/floating_window.txt"'
]

but the value printed is empty.

 -> G

This is the case no matter what window title I'm searching for. I wonder if there is something in my config that is causing the nested aerospace invocations to not see the current window list.

As far as the focus/always-on-top shortcomings, I can see how that would need some built-in solution. In my case, the window I'm trying to move has that behavior anyway so it's not a problem for me.

@gservat
Copy link

gservat commented Oct 21, 2024

@andsnpl: aerospace lives in /opt/homebrew/bin for me. This is added to $PATH by the homebrew init script in my zsh environment. Guessing when bash is loaded by aerospace, it inherits my zsh environment? Not sure why it doesn't work for you though as I'm guessing its in your path too.

@andsnpl
Copy link

andsnpl commented Oct 22, 2024

@gservat ah, I think that's it. You seem to be on Apple silicon and I'm still on Intel, so homebrew has different install behavior. My aerospace lives in /usr/local/bin, not /opt/homebrew/bin.

If you're using the start-at-login config option in aerospace.toml, then AeroSpace is being started for you by launchd, as it is for me. It's not (unless I'm much mistaken) executing any zsh environment for either of us. Instead what's happening is AeroSpace is manually inserting the /opt/homebrew dir into the path as described here, and probably nobody's realized that that's not good enough for Intel macs.

@gservat
Copy link

gservat commented Oct 22, 2024

@andsnpl: ahhh yes, good find! I wonder if it's worth filing a PR to update the default exec env variables to add /usr/local/bin to the path?

@farzadmf
Copy link

farzadmf commented Oct 22, 2024

I have the following script (defined as on-ws-change.sh and executable) to move Chrome PiP window:

#!/usr/bin/env sh

ws=${1:-$AEROSPACE_FOCUSED_WORKSPACE}

IFS=$'\n' all_wins=$(aerospace list-windows --all --format '%{window-id}|%{app-name}|%{window-title}|%{monitor-id}|%{workspace}')
IFS=$'\n' all_ws=$(aerospace list-workspaces --all --format '%{workspace}|%{monitor-id}')

chrome_pip=$(printf '%s\n' $all_wins | rg 'Picture in Picture')
target_mon=$(printf '%s\n' $all_ws | rg "$ws" | cut -d'|' -f2 | xargs)

move_win() {
  local win="$1"

  [[ -n $win ]] || return 0

  local win_mon=$(printf $win | cut -d'|' -f4 | xargs)
  local win_id=$(printf $win | cut -d'|' -f1 | xargs)
  local win_app=$(printf $win | cut -d'|' -f2 | xargs)
  local win_ws=$(printf $win | cut -d'|' -f5 | xargs)

  [[ $target_mon != $win_mon ]] && return 0
  [[ $ws == $win_ws ]] && return 0

  aerospace move-node-to-workspace --window-id $win_id $ws
}

move_win "${chrome_pip}"

And in my aerospace.toml, I have this:

exec-on-workspace-change = ['<full-path-to>/on-ws-change.sh']

@pencilcheck
Copy link

It looks like pip is a very common use case, safari pip seems to work out of box (perhaps it is due to the script I installed to fix zen browser pip?), would be nice if this is buildin instead

RammHub pushed a commit to RammHub/config that referenced this issue Dec 1, 2024
# After that, you can edit ~/.aerospace.toml to your liking

# You can use it to add commands that run after login to macOS user
session.
# 'start-at-login' needs to be 'true' for 'after-login-command' to work
# Available commands: https://nikitabobko.github.io/AeroSpace/commands
after-login-command = []

# You can use it to add commands that run after AeroSpace startup.
# 'after-startup-command' is run after 'after-login-command'
# Available commands : https://nikitabobko.github.io/AeroSpace/commands
after-startup-command = []

# Start AeroSpace at login
start-at-login = false

# Normalizations. See:
https://nikitabobko.github.io/AeroSpace/guide#normalization
enable-normalization-flatten-containers = true
enable-normalization-opposite-orientation-for-nested-containers = true

# See: https://nikitabobko.github.io/AeroSpace/guide#layouts
# The 'accordion-padding' specifies the size of accordion padding
# You can set 0 to disable the padding feature
accordion-padding = 30

# Possible values: tiles|accordion
default-root-container-layout = 'tiles'

# Possible values: horizontal|vertical|auto
# 'auto' means: wide monitor (anything wider than high) gets horizontal
orientation,
#               tall monitor (anything higher than wide) gets vertical
orientation
default-root-container-orientation = 'auto'

# Mouse follows focus when focused monitor changes
# Drop it from your config, if you don't like this behavior
# See
https://nikitabobko.github.io/AeroSpace/guide#on-focus-changed-callbacks
# See https://nikitabobko.github.io/AeroSpace/commands#move-mouse
# Fallback value (if you omit the key): on-focused-monitor-changed = []
on-focused-monitor-changed = ['move-mouse monitor-lazy-center']

# You can effectively turn off macOS "Hide application" (cmd-h) feature
by toggling this flag
# Useful if you don't use this macOS feature, but accidentally hit cmd-h
or cmd-alt-h key
# Also see:
https://nikitabobko.github.io/AeroSpace/goodies#disable-hide-app
automatically-unhide-macos-hidden-apps = false

# Possible values: (qwerty|dvorak)
# See https://nikitabobko.github.io/AeroSpace/guide#key-mapping
[key-mapping]
preset = 'qwerty'

# Gaps between windows (inner-*) and between monitor edges (outer-*).
# Possible values:
# - Constant:     gaps.outer.top = 8
# - Per monitor:  gaps.outer.top = [{ monitor.main = 16 }, {
monitor."some-pattern" = 32 }, 24]
#                 In this example, 24 is a default value when there is
no match.
#                 Monitor pattern is the same as for
'workspace-to-monitor-force-assignment'.
#                 See:
https://nikitabobko.github.io/AeroSpace/guide#assign-workspaces-to-monitors
[gaps]
inner.horizontal = 0
inner.vertical =   0
outer.left =       0
outer.bottom =     0
outer.top =        0
outer.right =      0

# 'main' binding mode declaration
# See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes
# 'main' binding mode must be always presented
# Fallback value (if you omit the key): mode.main.binding = {}
[mode.main.binding]

# All possible keys:
# - Letters.        a, b, c, ..., z
# - Numbers.        0, 1, 2, ..., 9
# - Keypad numbers. keypad0, keypad1, keypad2, ..., keypad9
# - F-keys.         f1, f2, ..., f20
# - Special keys.   minus, equal, period, comma, slash, backslash,
quote, semicolon, backtick,
#                   leftSquareBracket, rightSquareBracket, space, enter,
esc, backspace, tab
# - Keypad special. keypadClear, keypadDecimalMark, keypadDivide,
keypadEnter, keypadEqual,
#                   keypadMinus, keypadMultiply, keypadPlus
# - Arrows.         left, down, up, right

# All possible modifiers: cmd, alt, ctrl, shift

# All possible commands:
https://nikitabobko.github.io/AeroSpace/commands

# See: https://nikitabobko.github.io/AeroSpace/commands#exec-and-forget
# You can uncomment the following lines to open up terminal with alt +
enter shortcut (like in i3)
# alt-enter = '''exec-and-forget osascript -e '
# tell application "Terminal"
#     do script
#     activate
# end tell'
# '''

# See: https://nikitabobko.github.io/AeroSpace/commands#layout
alt-slash = 'layout tiles horizontal vertical'
alt-comma = 'layout accordion horizontal vertical'

# See: https://nikitabobko.github.io/AeroSpace/commands#focus
alt-h = 'focus left'
alt-j = 'focus down'
alt-k = 'focus up'
alt-l = 'focus right'

# See: https://nikitabobko.github.io/AeroSpace/commands#move
alt-shift-h = 'move left'
alt-shift-j = 'move down'
alt-shift-k = 'move up'
alt-shift-l = 'move right'

# See: https://nikitabobko.github.io/AeroSpace/commands#resize
alt-shift-minus = 'resize smart -50'
alt-shift-equal = 'resize smart +50'

# See: https://nikitabobko.github.io/AeroSpace/commands#workspace
alt-1 = 'workspace 1'
alt-2 = 'workspace 2'
alt-3 = 'workspace 3'
alt-4 = 'workspace 4'
alt-5 = 'workspace 5'
alt-6 = 'workspace 6'
alt-7 = 'workspace 7'
alt-8 = 'workspace 8'
alt-9 = 'workspace 9'
alt-a = 'workspace A' # In your config, you can drop workspace bindings
that you don't need
alt-b = 'workspace B'
alt-c = 'workspace C'
alt-d = 'workspace D'
alt-e = 'workspace E'
alt-f = 'workspace F'
alt-g = 'workspace G'
alt-i = 'workspace I'
alt-m = 'workspace M'
alt-n = 'workspace N'
alt-o = 'workspace O'
alt-p = 'workspace P'
alt-q = 'workspace Q'
alt-r = 'workspace R'
alt-s = 'workspace S'
alt-t = 'workspace T'
alt-u = 'workspace U'
alt-v = 'workspace V'
alt-w = 'workspace W'
alt-x = 'workspace X'
alt-y = 'workspace Y'
alt-z = 'workspace Z'

# See:
https://nikitabobko.github.io/AeroSpace/commands#move-node-to-workspace
alt-shift-1 = 'move-node-to-workspace 1'
alt-shift-2 = 'move-node-to-workspace 2'
alt-shift-3 = 'move-node-to-workspace 3'
alt-shift-4 = 'move-node-to-workspace 4'
alt-shift-5 = 'move-node-to-workspace 5'
alt-shift-6 = 'move-node-to-workspace 6'
alt-shift-7 = 'move-node-to-workspace 7'
alt-shift-8 = 'move-node-to-workspace 8'
alt-shift-9 = 'move-node-to-workspace 9'
alt-shift-a = 'move-node-to-workspace A'
alt-shift-b = 'move-node-to-workspace B'
alt-shift-c = 'move-node-to-workspace C'
alt-shift-d = 'move-node-to-workspace D'
alt-shift-e = 'move-node-to-workspace E'
alt-shift-f = 'move-node-to-workspace F'
alt-shift-g = 'move-node-to-workspace G'
alt-shift-i = 'move-node-to-workspace I'
alt-shift-m = 'move-node-to-workspace M'
alt-shift-n = 'move-node-to-workspace N'
alt-shift-o = 'move-node-to-workspace O'
alt-shift-p = 'move-node-to-workspace P'
alt-shift-q = 'move-node-to-workspace Q'
alt-shift-r = 'move-node-to-workspace R'
alt-shift-s = 'move-node-to-workspace S'
alt-shift-t = 'move-node-to-workspace T'
alt-shift-u = 'move-node-to-workspace U'
alt-shift-v = 'move-node-to-workspace V'
alt-shift-w = 'move-node-to-workspace W'
alt-shift-x = 'move-node-to-workspace X'
alt-shift-y = 'move-node-to-workspace Y'
alt-shift-z = 'move-node-to-workspace Z'

# See:
https://nikitabobko.github.io/AeroSpace/commands#workspace-back-and-forth
alt-tab = 'workspace-back-and-forth'
# See:
https://nikitabobko.github.io/AeroSpace/commands#move-workspace-to-monitor
alt-shift-tab = 'move-workspace-to-monitor --wrap-around next'

# See: https://nikitabobko.github.io/AeroSpace/commands#mode
alt-shift-semicolon = 'mode service'

# 'service' binding mode declaration.
# See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes
[mode.service.binding]
esc = ['reload-config', 'mode main']
r = ['flatten-workspace-tree', 'mode main'] # reset layout
f = ['layout floating tiling', 'mode main'] # Toggle between floating
and tiling layout
backspace = ['close-all-windows-but-current', 'mode main']

# sticky is not yet supported
nikitabobko/AeroSpace#2
#s = ['layout sticky tiling', 'mode main']

alt-shift-h = ['join-with left', 'mode main']
alt-shift-j = ['join-with down', 'mode main']
alt-shift-k = ['join-with up', 'mode main']
alt-shift-l = ['join-with right', 'mode main']

down = 'volume down'
up = 'volume up'
shift-down = ['volume set 0', 'mode main']
@thalesmello
Copy link

@farzadmf Your code breaks when I have multiple monitors connected (1 or 2), and I'm trying to switch to workspace named 1 or 2.

A quick fix would be to anchor the rg regex at the beginning of the string, when calculating the variable target_mon.

target_mon=$(printf '%s\n' $all_ws | rg "^$ws" | cut -d'|' -f2 | xargs)

Adding it here as reference in case there's anyone else trying to troubleshoot this.

@farzadmf
Copy link

farzadmf commented Dec 4, 2024

Oh cool, thanks for letting me know @thalesmello ; I didn't even think that someone would be using my code 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-proposal A well defined feature proposal
Projects
None yet
Development

No branches or pull requests