2

With the help of these

Get active window title in X

Obtain Active window using Python

I've managed to find out the name of the active window with

import os, re, sys
from subprocess import PIPE, Popen

def get_active_window_title():

    root = Popen( ['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout = PIPE )
    stdout, stderr = root.communicate()

    m = re.search( b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout )

    if m is not None:
        window_id = m.group( 1 )
        window = Popen( ['xprop', '-id', window_id, 'WM_NAME'], stdout = PIPE )
        stdout, stderr = window.communicate()

        match = re.match( b'WM_NAME\(\w+\) = (?P<name>.+)$', stdout )
        if match is not None:
            return match.group( 'name' ).decode( 'UTF-8' ).strip( '"' )

    return 'Active window not found'

if __name__ == '__main__':
    print( get_active_window_title() )

However, I'm also interested in the name of the process (firefox, rstudio...) that controls the window.

Any ideas on how to proceed?

teppo
  • 542
  • 8
  • 11

2 Answers2

1

Take a look a this answer. It uses a command line tool called xprop and one called wmctrl to get the PID of the active window. Once you have the PID, you can get just about any info you want about the process. For example, to get the name of the process, you can execute the following command with the python subprocess module:

ps -p 1337 -o comm=

The above will give you the command’s name while this:

ps -p 1337 -o command=

Will give you the commands full path.

Example (Ubuntu 17.10):

Command:

ps -p 1 -o comm=

Output:

init

Command:

ps -p 1 -o command=

Output:

/sbin/init
Steampunkery
  • 3,839
  • 2
  • 19
  • 28
1

Thank you @AnttiHaapala and @Steampunkery for the tips. Based on them I managed to revise my original code into an answer.

With xprop -root I get the window_id:

root = Popen( ['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout = PIPE )
stdout, stderr = root.communicate()
m = re.search( b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout )
window_id   = m.group( 1 )

Using the window_id, with xprop -id, I get the window name ("WM_NAME"):

window = Popen( ['xprop', '-id', window_id, 'WM_NAME'], stdout = PIPE )
stdout, stderr = window.communicate()
wmatch = re.match( b'WM_NAME\(\w+\) = (?P<name>.+)$', stdout )
windowname = wmatch.group( 'name' ).decode( 'UTF-8' ).strip( '"' )

as well as the names for the process ("WM_CLASS"):

processname1, processname2 = None, None
process = Popen( ['xprop', '-id', window_id, 'WM_CLASS'], stdout = PIPE )
stdout, stderr = process.communicate()
pmatch = re.match( b'WM_CLASS\(\w+\) = (?P<name>.+)$', stdout )
processname1, processname2 = pmatch.group( 'name' ).decode( 'UTF-8' ).split( ', ' )

The complete code with some error checking etc.:

import os, re, sys, time
from subprocess import PIPE, Popen


def get_activityname():

    root = Popen( ['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout = PIPE )
    stdout, stderr = root.communicate()
    m = re.search( b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout )

    if m is not None:

        window_id   = m.group( 1 )

        windowname  = None
        window = Popen( ['xprop', '-id', window_id, 'WM_NAME'], stdout = PIPE )
        stdout, stderr = window.communicate()
        wmatch = re.match( b'WM_NAME\(\w+\) = (?P<name>.+)$', stdout )
        if wmatch is not None:
            windowname = wmatch.group( 'name' ).decode( 'UTF-8' ).strip( '"' )

        processname1, processname2 = None, None
        process = Popen( ['xprop', '-id', window_id, 'WM_CLASS'], stdout = PIPE )
        stdout, stderr = process.communicate()
        pmatch = re.match( b'WM_CLASS\(\w+\) = (?P<name>.+)$', stdout )
        if pmatch is not None:
            processname1, processname2 = pmatch.group( 'name' ).decode( 'UTF-8' ).split( ', ' )
            processname1 = processname1.strip( '"' )
            processname2 = processname2.strip( '"' )

        return {
            'windowname':   windowname,
            'processname1': processname1,
            'processname2': processname2
            }

    return {
        'windowname':   None,
        'processname1': None,
        'processname2': None
        }


if __name__ == '__main__':
    a = get_activityname()
    print( '''
    'windowname':   %s,
    'processname1': %s,
    'processname2': %s
    ''' % ( a['windowname'], a['processname1'], a['processname2'] ) )

This should return the names for the window as well as the controlling process. It is able to fetch even the process name for RStudio which, for some reason, doesn't have a window name ("WM_NAME").

teppo
  • 542
  • 8
  • 11