6

Is there a way to automatically minimize a program after it hasn't had focus for a set amount of time?

4
  • 1
    Nice questtion! Will answer tonight if no one did. Am on mobile currently, will be home late... – Jacob Vlijm Dec 15 '16 at 9:04
  • Hi L42, did you notice the answer? please let me know if all is clear. – Jacob Vlijm Dec 16 '16 at 11:24
  • Yes, thank you! I will test it as soon as I can :) There's a specific program I wish this behaviour for, but your solution implements the behaviour for all programs - is that right? – L42 Dec 16 '16 at 11:44
  • right, but I can easily make it application- specific. Will add it as a second option. – Jacob Vlijm Dec 16 '16 at 11:48
8

Got it working perfectly, pretty much exactly as you describe.

1. Script to minimize windows after x time without focus

The background script below will minimize windows after an arbitrary time without focus.

The script

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

def getwindowlist():
    # get windowlist
    try:
        return [
            l.split()[0] for l in \
            subprocess.check_output(["wmctrl", "-l"]).decode("utf-8")\
            .splitlines()
            ]
    except subprocess.CalledProcessError:
        pass

def getactive():
    # get active window, convert to hex for compatibility with wmctrl
    wid = str(hex(int(
        subprocess.check_output(["xdotool", "getactivewindow"])\
        .decode("utf-8"))))
    return wid[:2]+str((10-len(wid))*"0")+wid[2:]

# round down on 2 seconds (match needs to be exact)
minitime = (int(sys.argv[1])/2)*2

wlist1 = []
timerlist = []

while True:
    time.sleep(2)
    wlist2 = getwindowlist()
    if wlist2:
        # clean up previous windowlist; remove non- existent windows
        try:
            timerlist = [
                wcount for wcount in timerlist if wcount[0] in wlist2
                ]
        except IndexError:
            pass
        for w in wlist2:
            # add new windows, zero record
            if not w in wlist1:
                timerlist.append([w, 0])
        # add two to account(s)
        for item in timerlist:
            item[1] += 2
        active = getactive()
        for w in timerlist:
            # minimize windows that reach the threshold
            if w[1] == minitime:
                subprocess.Popen(["xdotool", "windowminimize", w[0]])
            # set acoount of active window to zero
            w[1] = 0 if w[0] == active else w[1]
        wlist1 = wlist2

How to use

  1. The script needs both wmctrl and xdotool:

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

  3. Test- run it with the required time, in seconds (before minimizing), as argument, e.g.:

    python3 /path/to/minimize_timer.py 300
    

    ...to minimize windows after 5 minutes without focus

  4. If all works fine, add it to startup applications: Dash > Startup Applications > Add. Add the command:

    /bin/bash -c "sleep 15 && python3 /path/to/minimize_timer.py 300"
    

Notes

  • Running the script, I couldn't notice any additional burden to the processor.
  • The script "rounds" time on two seconds. If a window has focus for e.g. only 0.5 seconds, it might not be noticed as being "focussed".

Explanation

  • The script keeps record of all opened windows. Once per two seconds, the script adds two seconds to the windows' "account", unless the window has focus.
  • If the window has focus, its account isa set to 0
  • If the account reaches a certain threshold, set in the argument, the window is minimized by xdotool's windowminimize.

If a window no longer exists, it is removed from the record list.


2. Application specific version

The vesrion below will minimize all windows of an arbitrary application after x seconds.

The script

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

# --- set the application below
app = "gedit"
# ---

minitime = (int(sys.argv[1])/2)*2

def get(cmd):
    # helper function
    try:
        return subprocess.check_output(cmd).decode("utf-8").strip()
    except subprocess.CalledProcessError:
        pass

t = 0

while True:
    time.sleep(2)
    # first check if app is runing at all (saves fuel if not)
    pid = get(["pgrep", app])
    if pid:
        # if app is running, look up its windows
        windows = get(["xdotool", "search", "--all", "--pid", pid]).splitlines()
        if windows:
            # ...and see if one of its windows is focussed
            if get(["xdotool", "getactivewindow"]) in windows:
                # if so, counter is set to 0
                t = 0
            else:
                # if not, counter adds 2
                t += 2
        if t == minitime:
            # if counter equals the threshold, minimize app's windows
            for w in windows:
                subprocess.Popen(["xdotool", "windowminimize", w])
    else:
        t = 0

How to use

  1. The script needs xdotool:

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

  3. In the head section, set the application to minimize
  4. Test- run it with the required time, in seconds (before minimizing), as argument, e.g.:

    python3 /path/to/minimize_timer.py 300
    

    ...to minimize windows after 5 minutes without focus

  5. If all works fine, add it to startup applications: Dash > Startup Applications > Add. Add the command:

    /bin/bash -c "sleep 15 && python3 /path/to/minimize_timer.py 300"
    
3
  • Hiya. Made a couple of mods which make your code support multiple applications and custom PIDs. Repo is here: github.com/acenturyandabit/mini-miza but thanks for making the original answer :) – Thornkey Sep 3 '18 at 0:45
  • I find minitime = (int(sys.argv[1])/2)*2 works in Python2(Got 4 if 5 is passed) but not in Python3 (Got 5.0 if 5 is passed). – leaf Mar 11 '20 at 13:11
  • Is there a similar solution that can work on Windows 10? – Mike Jun 12 '20 at 9:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.