8

I am trying to write the Python script which prints the title of the active window using python in Mac OS.

Here is my code:

from AppKit import NSWorkspace
active_app_name = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()
print active_app_name

This code just prints name of the app like Google chrome or firefox, but not title. How to get title of the window?

kenorb
  • 155,785
  • 88
  • 678
  • 743
Bharath
  • 311
  • 1
  • 3
  • 5
  • 2
    Possible duplicate of [Finding the Current Active Window in Mac OS X using Python](https://stackoverflow.com/questions/373020/finding-the-current-active-window-in-mac-os-x-using-python) – kenorb May 28 '17 at 13:40

4 Answers4

8

Here is what I used to find both the active application name and window title on Mac OS X using Python by using Quartz API.

First of all, we need to add imports as required:

if sys.platform == "darwin":
    import applescript
    from AppKit import NSWorkspace
    from Quartz import (
        CGWindowListCopyWindowInfo,
        kCGWindowListOptionOnScreenOnly,
        kCGNullWindowID
    )

And then we can get the active app name and window title via the code below:

def getActiveInfo(event_window_num):
    try:
        if sys.platform == "darwin":
            app = NSWorkspace.sharedWorkspace().frontmostApplication()
            active_app_name = app.localizedName()

            options = kCGWindowListOptionOnScreenOnly
            windowList = CGWindowListCopyWindowInfo(options, kCGNullWindowID)
            windowTitle = 'Unknown'
            for window in windowList:
                windowNumber = window['kCGWindowNumber']
                ownerName = window['kCGWindowOwnerName']
                # geometry = window['kCGWindowBounds']
                windowTitle = window.get('kCGWindowName', u'Unknown')
                if windowTitle and (
                                event_window_num == windowNumber
                        or ownerName == active_app_name
                ):
                    # log.debug(
                    #     'ownerName=%s, windowName=%s, x=%s, y=%s, '
                    #     'width=%s, height=%s'
                    #     % (window['kCGWindowOwnerName'],
                    #        window.get('kCGWindowName', u'Unknown'),
                    #        geometry['X'],
                    #        geometry['Y'],
                    #        geometry['Width'],
                    #        geometry['Height']))
                    break

            return _review_active_info(active_app_name, windowTitle)
        if sys.platform == "win32":
            (active_app_name, windowTitle) = _getActiveInfo_Win32()
            return _review_active_info(active_app_name, windowTitle)
    except:
        log.error('Unexpected error: %s' % sys.exc_info()[0])
        log.error('error line number: %s' % sys.exc_traceback.tb_lineno)
    return 'Unknown', 'Unknown'
Jake W
  • 2,788
  • 34
  • 39
  • Could you give a complete shell example? I don't understand what the event_window_num arg is for. Or the _review_active_info(). – Yehosef May 22 '16 at 08:36
  • @Yehosef the event_window_num is from a mouse event or keyboard event captured, I think you can ignore this parameter safely. _review_active_info is also a custom function in my app to just verify app_name and window_title we get, you can also ignore this method. The core part of getting active app_name and window_title is shown in the sample code. – Jake W May 22 '16 at 12:40
  • Unfortunately, I just get an error straight away with `import applescript` : `ImportError: No module named applescript`. – mivk Jan 03 '21 at 10:25
4

There is no access to app title from NSWorkspace.sharedWorkspace().activeApplication().

But you can find the current window title by its PID:

For example:

from AppKit import NSWorkspace
pid = NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationProcessIdentifier']

Then find the right window using below code (it's stored in kCGWindowOwnerPID) as shown in below code:

Here is a complete shell example based on @JakeW's script:

#!/usr/bin/python
# Prints list of windows in the current workspace.
import sys
if sys.platform == "darwin":
    from AppKit import NSWorkspace
    from Quartz import (
        CGWindowListCopyWindowInfo,
        kCGWindowListOptionOnScreenOnly,
        kCGNullWindowID
    )

if sys.platform == "darwin":
    curr_app = NSWorkspace.sharedWorkspace().frontmostApplication()
    curr_pid = NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationProcessIdentifier']
    curr_app_name = curr_app.localizedName()
    options = kCGWindowListOptionOnScreenOnly
    windowList = CGWindowListCopyWindowInfo(options, kCGNullWindowID)
    for window in windowList:
        pid = window['kCGWindowOwnerPID']
        windowNumber = window['kCGWindowNumber']
        ownerName = window['kCGWindowOwnerName']
        geometry = window['kCGWindowBounds']
        windowTitle = window.get('kCGWindowName', u'Unknown')
        if curr_pid == pid:
            print("%s - %s (PID: %d, WID: %d): %s" % (ownerName, windowTitle.encode('ascii','ignore'), pid, windowNumber, geometry))
elif sys.platform == "win32":
    (active_app_name, windowTitle) = _getActiveInfo_Win32()

It will list details of the current active window including its title.

kenorb
  • 155,785
  • 88
  • 678
  • 743
  • This lists all windows of active application, not just the active window. E.g. in chrome open the developer tools on a separate window, you cannot distinguish which is active. – sivann May 31 '17 at 13:32
  • You need to add a break after curr_pid == pid:, and also check for existence of windowTitle – sivann May 31 '17 at 13:52
  • This worked, the higher voted answer by Jake W didn't work. – jason Aug 25 '20 at 05:39
1

As of macOS 10.6 and later it is better to use: frontmostApplication and if you want to get all of the applications listed you can call runningApplications method.

You can see more details at https://developer.apple.com/documentation/appkit/nsworkspace#overview

For example:

from AppKit import NSWorkspace
NSWorkspace.sharedWorkspace().runningApplications() // for getting all applications
NSWorkspace.sharedWorkspace().frontmostApplication() // for active window
Shay Dahan
  • 171
  • 1
  • 4
  • 4
    This answer is written well but doesn't address the OP's question about window title. Could you update your answer with how to get this title? – Samuel Jaeschke Jan 17 '21 at 23:16
1

I tried @kenorb's code but unlucky it can only get the app name, but no title content.

I finally found a way to do this with AppleScript: You can find the answer here: MacOSX: get foremost window title

First create a appleScript GetNameAndTitleOfActiveWindow.scpt

global frontApp, frontAppName, windowTitle

set windowTitle to ""
tell application "System Events"
    set frontApp to first application process whose frontmost is true
    set frontAppName to name of frontApp
    tell process frontAppName
        tell (1st window whose value of attribute "AXMain" is true)
            set windowTitle to value of attribute "AXTitle"
        end tell
    end tell
end tell

return {frontAppName, windowTitle}

You can test it first in your mac terminal:

osascript GetNameAndTitleOfActiveWindow.scpt

And then write this in python:

title = subprocess.check_output(['osascript', 'GetNameAndTitleOfActiveWindow.scpt'])