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

hy3:movefocus doesn't change monitor #2

Closed
VAWVAW opened this issue May 19, 2023 · 14 comments · Fixed by #126
Closed

hy3:movefocus doesn't change monitor #2

VAWVAW opened this issue May 19, 2023 · 14 comments · Fixed by #126

Comments

@VAWVAW
Copy link

VAWVAW commented May 19, 2023

When using multiple monitors, moving the focus or a window towards the other monitor doesn't change the monitor/workspace.

Expected behavior:

Using hy3:movefocus or hy3:movewindow against the edge of the monitor moves to the workspace on the next monitor like movefocus and i3/sway.

Actual behavior:

hy3:movefocus stops at the edge of the monitor.

@outfoxxed
Copy link
Owner

On the roadmap currently, just not my top priority.

@JustSimplyKyle
Copy link

JustSimplyKyle commented Oct 7, 2023

#!/bin/bash
NowWindow="$(hyprctl activewindow -j | jaq ".address")"
if [ "$1" == "right" ] ; then
  hyprctl dispatch hy3:movefocus r && sleep 0.05
  ThenWindow="$(hyprctl activewindow -j | jaq ".address")"
  if [ "$NowWindow" == "$ThenWindow" ]; then
    # hyprctl dispatch focusmonitor +1
    hyprctl dispatch movefocus r 
  fi
elif [ "$1" == "left" ] ; then
  hyprctl dispatch hy3:movefocus l && sleep 0.05
  ThenWindow="$(hyprctl activewindow -j | jaq ".address")"
  if [ "$NowWindow" == "$ThenWindow" ]; then
    # hyprctl dispatch focusmonitor -1
    hyprctl dispatch movefocus l 
  fi
fi

a... "workaround".

@ndom91
Copy link

ndom91 commented Dec 8, 2023

@JustSimplyKyle works for me! ❤️

For anyone else stumbling upon this. Should be called like this, for example:

bind = $mainMod, H, exec, movefocus.sh left
bind = $mainMod, L, exec, movefocus.sh right

@Safenein
Copy link

I modified the script so that up and down is also working.
That is a nice workaround, thank you.

#!/bin/bash
NowWindow="$(hyprctl activewindow -j | jq ".address")"

hyprctl dispatch hy3:movefocus "$1"  # && sleep 0.05
ThenWindow="$(hyprctl activewindow -j | jq ".address")"
if [ "$NowWindow" == "$ThenWindow" ]; then
  hyprctl dispatch movefocus "$1"
fi

Deleting the sleep 0.05 is working fine for me. You may put it back if you experience any issues.

bind = $mainMod, H, exec, movefocus.sh l
bind = $mainMod, L, exec, movefocus.sh r
bind = $mainMod, K, exec, movefocus.sh u
bind = $mainMod, J, exec, movefocus.sh d

@oddlySpecificLama
Copy link

oddlySpecificLama commented Mar 26, 2024

Hi guys, here the same behavior for "movetoworkspace", or at least a ... sloppy solution for a problem that has no real other solution ("implemented") yet. I feel dirty myself for coding this, and not just reading into the C++ Code.

Basically does the same as the code above: if the window was able to move, do nothing. If it wasn't, move it to ANOTHER workspace. Not the correct one. Not on the correct side. Works best with 2 screens and a low amount of windows on each workspace. This is just a small quick fix.

movescreen.sh:

PREPOS=$(hyprctl activewindow -j | jq ".at")
hyprctl dispatch hy3:movewindow $1
sleep 0.05
POSTPOS=$(hyprctl activewindow -j | jq ".at")

if [[ ! "$PREPOS" == "$POSTPOS" ]]
then
    exit
fi


# position didn't change -> move to next workspace!
ACTIVEWORKSPACE=$(hyprctl activewindow -j | jq ".workspace.id")
for i in $(seq 0 100)
do
    WORKSPACEID=$(hyprctl monitors -j | jq ".[$i].activeWorkspace.id")
    if [[ "$WORKSPACEID" == "null" ]]
    then
        break
    fi

    if [[ "$WORKSPACEID" == "$ACTIVEWORKSPACE" ]]
    then
        continue
    fi

    hyprctl dispatch movetoworkspace "$WORKSPACEID"
    exit
done

And in the hyprland.conf:

bind=SUPERSHIFT,H,exec,/home/BLA/config/hypr/movescreen.sh l
bind=SUPERSHIFT,L,exec,/home/BLA/config/hypr/movescreen.sh r
bind=SUPERSHIFT,K,exec,/home/BLA/config/hypr/movescreen.sh u
bind=SUPERSHIFT,J,exec,/home/BLA/config/hypr/movescreen.sh d

@JustSimplyKyle
Copy link

iirc, you can do +1 in the argument, will try one I got home

@oddlySpecificLama
Copy link

With what command exactly?
With "hyprctl dispatch movetoworkspace +1" it does work, but sadly not as intended. It moves the window, but only to the workspace number+1, not to the other screen.

@JustSimplyKyle
Copy link

I was thinking of the dispatcher movewindow, and mon:(+/-)1 as its argument

@oddlySpecificLama
Copy link

Oh, i didn't know that! This works perfectly as well!
So basically:
hyprctl dispatch movewindow mon:+1

Also, i found a small bug as well: if you move a window that was first on the left half of a screen to the top half, the position itself doesn't change. But position and size together should be good enough to pin down if the window actually moved. For this dirty dirty script, i won't care about the edge case.

So to summarize:

#!/bin/bash

PREPOS=$(hyprctl activewindow -j | jq ".at")
PRESIZE=$(hyprctl activewindow -j | jq ".size")
hyprctl dispatch hy3:movewindow $1
sleep 0.05
POSTPOS=$(hyprctl activewindow -j | jq ".at")
POSTSIZE=$(hyprctl activewindow -j | jq ".size")

if [[ ! "$PREPOS" == "$POSTPOS" ]] || [[ ! "$PRESIZE" == "$POSTSIZE" ]]
then
    exit
fi

hyprctl dispatch movewindow mon:+1

Of course it still doesn't move to the correct side, but that's for later, i suppose.

@JustSimplyKyle
Copy link

Question: Does Hyprland order the Monitor's ID deterministicly? If so, for a purely horizontal layout, it may be possible to put the order in an array, and move it accordingly to the input(l,r,u,d)

@oddlySpecificLama
Copy link

I just checked with a 3 monitor setup. Sadly, it does not. At least when i reorder the monitors afterwards, "+1" still goes into the same direction as beforehand.

@JustSimplyKyle
Copy link

#!/bin/bash

mapfile -t SortedMonitors <<< "$(hyprctl monitors -j | jq -r 'sort_by(.x) | .[] | .id')"
# SortedMonitors=(2 0 1)
CurrentMonitor="$(hyprctl activeworkspace -j | jq ".monitorID")"
Direction="$1"
SortedMonitorsSize="${#SortedMonitors[@]}"

declare CurrentIndex

# find the index of the current monitor in the sorted monitors array
for index in "${!SortedMonitors[@]}"; do
    if [[ "${SortedMonitors[$index]}" == "$CurrentMonitor" ]]; then
        CurrentIndex="$index"
        break
    fi
done

if [[ $Direction == "r" ]]; then
    ((CurrentIndex++))
elif [[ $Direction == "l" ]]; then
    ((CurrentIndex--))
fi

# Loopback logic
if (( CurrentIndex == SortedMonitorsSize )); then
    CurrentIndex=0
elif (( CurrentIndex < 0 )); then
    CurrentIndex=$((SortedMonitorsSize - 1))
fi

NextMonitorId="${SortedMonitors[$CurrentIndex]}"

hyprctl dispatch movewindow mon:"$NextMonitorId"

@oddlySpecificLama , use this with arguments r or l, can you confirm that would this work?
I only have two monitors, but with my primitive testing, this script shall work with a purely horizontal layout

@sliedes
Copy link

sliedes commented Aug 7, 2024

I was unhappy with the latency introduced by the movefocus script (switching windows felt slow, even after removing the sleep - timing the script, executing it tooks 50 ms). Turns out hyprctl is rather slow to load, probably due to linking to unnecessarily many dynamic libraries. So here's my hacked version that:

  • uses socat
  • combines the activewindow and hy3:movefocus calls
  • changes "left" and "right" to "l" and "r" for consistency with movefocus and hy3:movefocus
  • executes in about 12 ms
  • fixes some bashisms so it can be used with the faster dash shell (though this didn't turn out to be significant)
SOCAT="socat - $XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket.sock"
if [ "$1" = "r" ] ; then
    NowWindow="$(echo -n '[[BATCH]]j/activewindow;/dispatch hy3:movefocus r' |$SOCAT |grep -vE '^(ok)?$' | jaq '.address')"
    ThenWindow="$(echo -n 'j/activewindow' |$SOCAT | jaq ".address")"
    if [ "$NowWindow" = "$ThenWindow" ]; then
        echo -n '/dispatch movefocus r' |$SOCAT
    fi
elif [ "$1" = "l" ] ; then
    NowWindow="$(echo -n '[[BATCH]]j/activewindow;/dispatch hy3:movefocus l' |$SOCAT |grep -vE '^(ok)?$' | jaq ".address")"
    ThenWindow="$(echo -n 'j/activewindow' |$SOCAT| jaq ".address")"
    if [ "$NowWindow" = "$ThenWindow" ]; then
        echo -n '/dispatch movefocus l' |$SOCAT
    fi
fi

I think the grep thing is a bit ugly, but what can you do, hyprctl sometimes gives JSON and sometimes "ok". :( Definitely feels much snappier, though!

@sliedes
Copy link

sliedes commented Aug 7, 2024

I was unhappy with the latency introduced by the movefocus script (switching windows felt slow, even after removing the sleep - timing the script, executing it tooks 50 ms). Turns out hyprctl is rather slow to load, probably due to linking to unnecessarily many dynamic libraries. So here's my hacked version that:

... or this PR for hyprctl to link against much less libraries: hyprwm/Hyprland#7212

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants