I frequently use Ctrl+Super+Arrow -Keys to move windows around. However, with a multiple monitor set up, the shortcuts only move the windows on the current screen.
**Example of my situation:
I have 3 monitors and I have an instance of
Chrome open in my center monitor.
- When I hit Ctrl+Super+Arrow (left)the window splits to the left half of my center monitor.
- When I repeat, the window does not move.
What I’d like to see instead is that in
[2.], the window moves to the right half of the left most monitor, and so on
How do I achieve this behaviour?
Here is Solutions:
We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.
Move your semi- maximized windows across multiple screens (“aero- snap” alike)
The script below does exactly as you describe. It can be used on any number of screens. The script is optimized for Unity, but can easily be edited to fit other window managers.
It turned out to be a bit more complicated than I thought, since the script should take into account that the user possibly set the launcher to only appear on the leftmost screen (or not). The targeted positions (and targeted window sizes) should be calculated accordingly.
- The script moves the windows through all connected screens, subsequently switching through the “halves” of the screens, from left to right and vice versa.
- The script reads the sizes of the screens and sets the window size, to half the screen size accordingly.
- The script reads the settings on the launcher (if the launcher appears on only the first screen or on all), and calculates the targeted window sizes accordingly.
- The script does not take into account the possibly set autohide option for the launcher. The reason is that updating the windowsize once the launcher hides or shows up would take a background script, and quite an other story to code.
- The windows are moved and resized by a combination of
wmctrl– commands. Since these commands can have some “characteristic behaviour” in combination with Unity, there is a possiblility minor changes can be useful on your system. I tested it on two (quite different) systems however, working fine on both.
#!/usr/bin/env python3 import subprocess import sys # --- set possibly wanted marge (on the right side of the window) below marge = 0 # --- set set launcher width below (default = 65) default_launcherwidth = 65 # --- move = sys.argv get = lambda cmd: subprocess.check_output( ["/bin/bash", "-c", cmd]).decode("utf-8") screendata = [l for l in get("xrandr").splitlines() if " connected" in l] # get the primary screen's position pr = [l.split() for l in screendata if "primary" in l] i = pr.index("primary"); s = pr[i+1] primary= [int(s.split("x")), int(s.split("+")[-2])] # general screen list screendata = [ [s for s in l.split() if s.count("+") == 2] for l in screendata ] screendata = [ [int(s.split("x")),int(s.split("+")[-2])] for s in screendata ] screendata.sort(key=lambda x: x); primary = screendata.index(primary) def launcher_size(): launcherset = get( "dconf read /org/compiz/profiles/unity/plugins/unityshell/num-launchers" ).strip() l_size_0 = 65; l_size_1 = l_size_0 if launcherset == "0" else 0 return [l_size_0, l_size_1] def magnets(index): l_size = l_sizes if index == primary else l_sizes screen = screendata[index] screenwidth = screen; shift = screen parts = (screenwidth - l_size)/2; virtual_mid = screenwidth - parts + shift left_trigger = shift + l_size return [left_trigger, int(virtual_mid), int(parts)] def find_screen(x_loc): scr_index = len([scr for scr in screendata if x_loc >= scr])-1 scr_index = scr_index if scr_index >= 0 else 0 screen = screendata[scr_index] return [scr_index, screen] def get_active(): active = hex(int(get("xdotool getactivewindow").strip())) active = active[:2]+(10-len(active))*"0"+active[2:] x_pos = int([l.split() for l in get("wmctrl -lG").splitlines() \ if l.startswith(active)]) return [active, x_pos] def decide(x_loc, active): current_scr = find_screen(x_loc) triggers = magnets(current_scr) width = triggers index = current_scr if move == "left": if x_loc <= triggers: if x_loc == triggers: if index != 0: alter = magnets(index-1) width = alter[-1] target = alter else: target = triggers else: target = triggers elif x_loc > triggers: target = triggers elif move == "right": if x_loc >= triggers: if index != len(screendata)-1: alter = magnets(index+1) width = alter[-1] target = alter else: target = triggers elif x_loc < triggers: target = triggers subprocess.call([ "wmctrl", "-r", ":ACTIVE:","-b", "remove,maximized_vert,maximized_horz" ]) subprocess.call(["wmctrl", "-ir", active, "-e", "0,"+str(target)+",400,"+\ str(int(width)-marge)+",200"]) subprocess.call([ "wmctrl", "-ir", active, "-b", "toggle,maximized_vert" ]) l_sizes = launcher_size() w_data = get_active() active = w_data x_loc = w_data decide(x_loc, active)
How to use
The scrpt needs both
sudo apt-get instal xdotool wmctrl
Copy the script into an empty file, save it as
Test- run the script from a terminal window by (repeatedly) the command:
python3 /path/to/move_window.py right
which should move the window through your screens to the rignt, and:
python3 /path/to/move_window.py left
which should move the window through your screens to the left.
If all works fine, add both commands to shortcut keys: choose: System Settings > “Keyboard” > “Shortcuts” > “Custom Shortcuts”. Click the “+” and add the commands to two shortcut keys of your choice.
The launcher width is set to
65px(corresponding to icon size
17pxborders, which is the default). If the set width is different, it should be set correctly in the head of the script, as indicated in the section:
# --- set set launcher width below (default = 65) default_launcherwidth = 65 # ---
In the headsection of the script, there is furthermore a line:
marge = 0
which sets the empty marge at the right side of the moved screen. Change it if you like to another value.
Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂