11

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.

3
13

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
9
  • +1. I always love your answers Jacob. Nice work. – Parto Aug 25 '15 at 5:52
  • I had to change limit < pos < span to limit <= pos < span to get it working. Anyway this is really nice. However I'm not sure if I want to have it working this way (dimming the other screen). I'll try to modify it to make single bright 'pulse' when active screen changes. – korda Aug 25 '15 at 5:56
  • I've also added exit handler, it resets screen brightness to normal value. (so it won't stay dimmed when I've killed script during testing). Not sure if I should add it here - I'm not much into python, so I'm not sure if I did it right (but it works) – korda Aug 25 '15 at 6:05
  • I've edited it your answer and added it. – korda Aug 25 '15 at 6:17
  • 1
    @JacobVlijm Wow! you rock – dhiya Aug 25 '15 at 14:53
1

I've also found another solution, that is bit different from what I wanted in the first place, but works fine too.

  1. Install compizconfig-settings-manager compiz-plugins
  2. Run ccsm
  3. In Effects section enable Animations plugin
  4. In Focus Animation edit and select desired animation.

Only wave effect worked... So if you don't like it, you will have face as sad as mine.

1
  • Dodge also works for me, but only when the raising window was hidden or partly-hidden behind another. Fade gives an odd, unpleasant flash. – Paddy Landau Sep 1 '15 at 8:25

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.