Ubuntu – How to highlight current screen (or window)

compizmultiple-monitorsscriptsunitywindow-manager

I'm using two screen setup at work and while it usually helps more than it hurts, I have some issues with it.

One of them is problem with trailing focus – sometimes I make mistake of typing on wrong screen (focus is trailing my cursor, but it's not always easy to notice that cursor is on other screen when you do things in a rush). This is very annoying when instead of typing I cause tons of different actions (one-key-shortcuts in thunderbird).

Is there a way to better highlight active screen or window (for example using easily visible border – even for maximized windows)?

EDIT:

I think nice solution would be some kind of short animation when window receives focus.

Best Answer

Highlight the focussed screen (or dim- flash on focus change, see EDIT further below)

In a side-by-side dual monitor setup (left-right), the script below will set the brightness of the monitor with the focussed window to "normal" (100%), while other one is dimmed to 60%.

If the focus changes, the brightness will follow the focus:

focus on (a window) on the right screen enter image description here

focus on (a window) on the left screen enter image description here

The script

#!/usr/bin/env python3
"""
In a side-by-side dual monitor setup (left-right), the script below will set
the brightness of the monitor with the focussed window to "normal" (100%),
while other one is dimmed to 60%. If the focus changes, the brightness will
follow the focus
"""
import subprocess
import time

def get_wposition():
    # get the position of the currently frontmost window
    try:
        w_data = subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8").splitlines()
        frontmost = subprocess.check_output(["xprop", "-root", "_NET_ACTIVE_WINDOW"]).decode("utf-8").split()[-1].strip()
        z = 10-len(frontmost); frontmost = frontmost[:2]+z*"0"+frontmost[2:]
        return [int(l.split()[2]) for l in w_data if frontmost in l][0]
    except subprocess.CalledProcessError:
        pass

def get_onscreen():
    # get the size of the desktop, the names of both screens and the x-resolution of the left screen
    resdata = subprocess.check_output(["xrandr"]).decode("utf-8")
    if resdata.count(" connected") == 2:
        resdata = resdata.splitlines()
        r = resdata[0].split(); span = int(r[r.index("current")+1])
        screens = [l for l in resdata if " connected" in l]
        lr = [[(l.split()[0], int([s.split("x")[0] for s in l.split() if "+0+0" in s][0])) for l in screens if "+0+0" in l][0],
               [l.split()[0] for l in screens if not "+0+0" in l][0]]
        return [span, lr]
    else:
        print("no second screen seems to be connected")

def scr_position(span, limit, pos):
    # determine if the frontmost window is on the left- or right screen
    if limit < pos < span:
        return [right_scr, left_scr]
    else:
        return [left_scr, right_scr]

def highlight(scr1, scr2):
    # highlight the "active" window, dim the other one
    action1 = "xrandr", "--output", scr1, "--brightness", "1.0"
    action2 = "xrandr", "--output", scr2, "--brightness", "0.6"
    for action in [action1, action2]:
        subprocess.Popen(action)

# determine the screen setup
screendata = get_onscreen()
left_scr = screendata[1][0][0]; right_scr = screendata[1][1]
limit = screendata[1][0][1]; span = screendata[0]

# set initial highlight
oncurrent1 = scr_position(span, limit, get_wposition())
highlight(oncurrent1[0], oncurrent1[1])

while True:
    time.sleep(0.5)
    pos = get_wposition()
    # bypass possible incidental failures of the wmctrl command
    if pos != None:
        oncurrent2 = scr_position(span, limit, pos)
        # only set highlight if there is a change in active window
        if oncurrent2 != oncurrent1:
            highlight(oncurrent1[1], oncurrent1[0])
        oncurrent1 = oncurrent2

How to use

  1. The script needs wmctrl:

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

  3. Test- run it by the command:

    python3 /path/to/highlight_focus.py
    

    With the second monitor connected, test if the script works as expected.

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

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

Notes

  • The script is extremely low on resources. To "save fuel", the screen setup; resolutions, span size etc. is read only once, during startup of the script (not included in the loop). That implies that you have to restart the script if you connect/disconnect the second monitor.

  • If you added it to startup applications, it means you have to log out/in after changes in monitor configuration.

  • If you'd prefer another brightness percentage for the dimmed screen, change the value in the line:

    action2 = "xrandr", "--output", scr2, "--brightness", "0.6"
    

The value can be between 0,0 (black screen) and 1.0 (100%).

Explanation

enter image description here

On startup of the script, it determines:

  • the spanning resolution of both screens
  • the x-resolution of the left screen
  • the names of both screens

Then, in a loop (once per second), it:

  • checks the position of the active window with the commands:

    • wmctrl -lG (to get the list of windows and their positions)
    • xprop -root _NET_ACTIVE_WINDOW (to get the id of the frontmost window)

If the window's (x-) position is greater then the x-resolution of the left screen, the window apparently is on the right screen, unless it is greater then the spanning size of the two screens (then it would be on the workspace on the right). therefore:

if limit < pos < span:

determines if the window is on the right screen (where limitis x-res of the left screen, pos is the window's x-position and span is the combined x-res of both screens).

If there is a change in the position of the frontmost window (on left screen or right screen), the script sets the brightness of both screens with the xrandr command:

xrandr --output <screen_name> --brightness <value>

EDIT

Dim-flash the focussed screen instead of a permanent dimmed "unfocussed" screen

As requested in a comment and in chat, below a version of the script that gives a short dim flash on the newly focussed screen instead:

#!/usr/bin/env python3
"""
In a side-by-side dual monitor setup (left-right), the script below will give
a short dim- flash on the newly focussed screen if the focussed screen changes
"""

import subprocess
import time

def get_wposition():
    # get the position of the currently frontmost window
    try:
        w_data = subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8").splitlines()
        frontmost = subprocess.check_output(["xprop", "-root", "_NET_ACTIVE_WINDOW"]).decode("utf-8").split()[-1].strip()
        z = 10-len(frontmost); frontmost = frontmost[:2]+z*"0"+frontmost[2:]
        return [int(l.split()[2]) for l in w_data if frontmost in l][0]
    except subprocess.CalledProcessError:
        pass

def get_onscreen():
    # get the size of the desktop, the names of both screens and the x-resolution of the left screen
    resdata = subprocess.check_output(["xrandr"]).decode("utf-8")
    if resdata.count(" connected") == 2:
        resdata = resdata.splitlines()
        r = resdata[0].split(); span = int(r[r.index("current")+1])
        screens = [l for l in resdata if " connected" in l]
        lr = [[(l.split()[0], int([s.split("x")[0] for s in l.split() if "+0+0" in s][0])) for l in screens if "+0+0" in l][0],
               [l.split()[0] for l in screens if not "+0+0" in l][0]]
        return [span, lr]
    else:
        print("no second screen seems to be connected")

def scr_position(span, limit, pos):
    # determine if the frontmost window is on the left- or right screen
    if limit < pos < span:
        return [right_scr, left_scr]
    else:
        return [left_scr, right_scr]

def highlight(scr1):
    # highlight the "active" window, dim the other one
    subprocess.Popen([ "xrandr", "--output", scr1, "--brightness", "0.3"])
    time.sleep(0.1)
    subprocess.Popen([ "xrandr", "--output", scr1, "--brightness", "1.0"])

# determine the screen setup
screendata = get_onscreen()
left_scr = screendata[1][0][0]; right_scr = screendata[1][1]
limit = screendata[1][0][1]; span = screendata[0]

# set initial highlight
oncurrent1 = []

while True:
    time.sleep(0.5)
    pos = get_wposition()
    # bypass possible incidental failures of the wmctrl command
    if pos != None:
        oncurrent2 = scr_position(span, limit, pos)
        # only set highlight if there is a change in active window
        if oncurrent2 != oncurrent1:
            highlight(oncurrent2[0])
        oncurrent1 = oncurrent2
Related Question