Ubuntu – How to gracefully close all instances of gnome-terminal

command linegnome-terminalshortcut-keys

I am trying to find out how to close all windows of Terminal (quit all instances of gnome-terminal) at once, cleanly. By "cleanly", I mean that it doesn't just simply kill all the instances at once, which is what I already have with this alias:

alias poof='/usr/bin/killall gnome-terminal'    

What I want to do is to make it behave as the Terminal application behaves in Mac OS X. On that platform, when I hit "command-Q" (a/k/a "Apple-Q") in Terminal, all the windows are closed, but if there are processes running in any particular Terminal window, I get a dialog box warning me and asking me if I still want to close the window. This way I can make sure I don't kill a process I forgot about (e.g. editing a file with vim). In other words, it acts as though I have clicked the close button on each window.

This question has been asked in one form or another before, it has not been answered satisfactorily (unless I misunderstood the answer). Surely there is a way to do this in Ubuntu 14.04? Either in the command line or using a keyboard shortcut (or both)?

(And please forgive me if I am not following any stylistic formats correctly, as I am new.)

Best Answer

Even the "friendliest" kill- command will close the terminal without asking. Also man gnome-terminal does not give any solution to close the window like in the GUI.

You can however make a script raise (all) gnome-terminal windows and simulate Ctrl+Shift+Q.

A complexity is that this will not work when the windows are spread over different workspaces. The script below therefore looks up the gnome-terminal windows on the current workspace and takes care of them as explained above.

The script

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

def get_res():
    # get resolution
    xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

try:
    pid = subprocess.check_output(["pidof", "gnome-terminal"]).decode("utf-8").strip()
except:
    pass
else:
    res = get_res()
    ws = subprocess.check_output(["wmctrl", "-lpG"]).decode("utf-8").splitlines()
    for t in [w for w in ws if pid in w]:
        window = t.split()
        if all([0 < int(window[3]) < res[0], 0 < int(window[4]) < res[1]]) :
            w_id = window[0]    
            subprocess.Popen(["wmctrl", "-ia", w_id])
            subprocess.call(["xdotool", "key", "Ctrl+Shift+Q"])
            time.sleep(0.2)

How to use

  1. The script needs both wmctrl and xdotool

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

  3. Test-run it by the command:

    python3 /path/to/close_allterminals.py
    

    Example: four gnome-terminal windows opened, in the top-left one is a process running:

    After running the command, three are closed automatically, the one with the running process gets a prompt:

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

     python3 /path/to/close_allterminals.py
    

Edit

The version below also takes care of gnome-terminal windows on other workspace: all windows are moved to the current workspace before they are closed in a safe way.

An example:
I have in total six gnome-terminal windows open on four different workspaces, many of them have processes running in it:

If I run the script, all gnome-terminal windows are orderly moved to the current workspace and raised. Idle windows are closed automatically, the ones with a running process are prompted:

The script

Set it up like the first version.

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

def get_res():
    # get resolution
    xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
    pos = xr.index("current")
    return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]

try:
    pid = subprocess.check_output(["pidof", "gnome-terminal"]).decode("utf-8").strip()
except:
    pass
else:
    res = get_res()
    ws = subprocess.check_output(["wmctrl", "-lpG"]).decode("utf-8").splitlines()
    matches = [t.split() for t in [w for w in ws if pid in w]]
    pos = 100
    for match in matches:
        w_id = match[0]
        subprocess.call(["xdotool", "windowmove", "--sync", match[0], str(pos), str(pos/2) ])
        subprocess.call(["wmctrl", "-ia", w_id])
        subprocess.call(["xdotool", "key", "Ctrl+Shift+Q"])
        pos = pos+100