Ubuntu – How to make equally sized windows in corners of the screen

shortcut-keyswindowwindow-managerwmctrlxdotool

I recently saw this answer to a great question, and I wondered, is this also possible on Ubuntu GNOME 15.10 with GNOME 3.18 and GDM, as well as on Compiz as the answer to that question shows?

But the keyboard shortcuts aren't so important for me, I just really want to be able to drag windows into the corners and have them automatically resize into those corners rather than on the sides when I release my mouse.

Best Answer

On the edge of posting a duplicate of this one (but the question slightly differs), the script below does what you describe, if you run it with the arguments

python3 /path/to/script.py 2 2

However, if there are more than four windows (or more than the cells of a grid, if you use other arguments than 2 2), the script places only the four oldest windows in the grid.

What it does

When four windows are opened, randomly placed on the screen:

enter image description here

running the script will arrange them in a grid:

enter image description here

The script

#!/usr/bin/env python3
import subprocess
import sys

#--- set your preferences below: padding between windows, margin(s)
cols = int(sys.argv[1]); rows = int(sys.argv[2]); padding = 10; left_margin = 0; top_margin = 30
#---

get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_res():
    xr = get("xrandr").split(); pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

def check_window(w_id):
    w_type = get("xprop -id "+w_id)
    if " _NET_WM_WINDOW_TYPE_NORMAL" in w_type:
        return True
    else:
        return False

# get resolution
res = get_res()
# define (calculate) the area to divide
area_h = res[0] - left_margin; area_v = res[1] - top_margin
# create a list of calculated coordinates
x_coords = [int(left_margin+area_h/cols*n) for n in range(cols)]
y_coords = [int(top_margin+area_v/rows*n) for n in range(rows)]
coords = sum([[(cx, cy) for cx in x_coords] for cy in y_coords], [])
# calculate the corresponding window size, given the padding, margins, columns and rows
w_size = [str(int(area_h/cols - padding)), str(int(area_v/rows - padding))]
# find windows of the application, identified by their pid
wlist = [w.split()[0] for w in get("wmctrl -lp").splitlines()]
w_list = [w for w in wlist if check_window(w) == True][:cols*rows]
print(w_list)

# remove possibly maximization, move the windows
for n, w in enumerate(w_list):
    data = (",").join([str(item) for item in coords[n]])+","+(",").join(w_size)
    cmd1 = "wmctrl -ir "+w+" -b remove,maximized_horz"
    cmd2 = "wmctrl -ir "+w+" -b remove,maximized_vert"
    cmd3 = "wmctrl -ir "+w+" -e 0,"+data
    for cmd in [cmd1, cmd2, cmd3]:
        subprocess.Popen(["/bin/bash", "-c", cmd])

How to use

  1. The script needs both xdotool and wmctrl:

    sudo apt-get install xdotool wmctrl
    
  2. Copy the script into an empty file, save it as twobytwo.py

  3. Test- run it by opening four windows (at least one terminal window to run the command), the run the command:

    python3 /path/to/twobytwo.py 2 2
    

    The windows should move into a grid of 4, as in the second image

  4. If all works fine, add it to a shortcut key: choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:

    python3 /path/to/twobytwo.py 2 2
    

Note(s)

  • in the head section, there is a section:

    left_margin = 0
    

    I set this to zero, since gnome does not have the launcher on the left. For Unity, this should be (at least) 65, depending on the set width of the launcher.

  • As mentioned, the script, as it is, grids the four oldest windows. That means if you need more windows to be placed in the same grid, the script needs an edit. Please mention if so.