AppKit not dynamically sensing the Frontmost App

I'm using Appkit in Python to have the computer sense the frontmost app. It will correctly sense the frontmost app at first but when I change the frontmost app and leave the terminal running, it will not update the new information. For example, the following code will work:



from AppKit import NSWorkspace

active_app_name = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()





But now suppose I make Chrome rather than Excel the frontmost app and run the following program on terminal. Then after the terminal prints 'Chrome', I click on the app 'Excel', the terminal will continue to print 'Chrome' and it will never sense that Excel is the frontmost app.



from AppKit import NSWorkspace

while True:

active_app_name = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()

print (active_app_name)

if active_app_name == 'Microsoft Excel':

pass

# do stuff

else:

time.sleep(5)


I want AppKit to be able to sense the new frontmost app when I make changes to which the frontmost app is.

MacBook Pro, OS X Yosemite (10.10.1)

Posted on Aug 24, 2018 1:43 AM

Reply
Question marked as Top-ranking reply

Posted on Aug 24, 2018 1:50 PM

Well, I'm not all that familiar with Python (I'm a Ruby guy), but various scripting languages have been extended to provide access (bridges) to the Cocoa APIs. You must be running one of those (such as PyObjC) to be able to import stuff from the AppKit.


Since it deals with the user interface, AppKit is designed to work with a run loop - that is, the system periodically loops through the various UI objects and passes events (clicks, drags, keys, etc) on to those applications that are interested in them. In your case, NSWorkspace.sharedWorkspace checks for workspace events such as when applications change, and makes that information available either through notifications or its class methods.


The while loop you are using is not letting the system access events (assuming you even have a run loop), so your information is not getting updated. Note that even in a Cocoa application this kind of practice will result in the UI getting blocked. The solution is to allow the system to process events, either through normal "gaps" in the execution of your code, or by manually providing a means to do so.

14 replies
Question marked as Top-ranking reply

Aug 24, 2018 1:50 PM in response to kyle76

Well, I'm not all that familiar with Python (I'm a Ruby guy), but various scripting languages have been extended to provide access (bridges) to the Cocoa APIs. You must be running one of those (such as PyObjC) to be able to import stuff from the AppKit.


Since it deals with the user interface, AppKit is designed to work with a run loop - that is, the system periodically loops through the various UI objects and passes events (clicks, drags, keys, etc) on to those applications that are interested in them. In your case, NSWorkspace.sharedWorkspace checks for workspace events such as when applications change, and makes that information available either through notifications or its class methods.


The while loop you are using is not letting the system access events (assuming you even have a run loop), so your information is not getting updated. Note that even in a Cocoa application this kind of practice will result in the UI getting blocked. The solution is to allow the system to process events, either through normal "gaps" in the execution of your code, or by manually providing a means to do so.

Aug 24, 2018 3:01 PM in response to kyle76

I saw your code early this morning but have been traveling all day. The following code will print out the current frontmost application that I click on whether that is Safari, Sublime Text 3, or Terminal, which were the applications I tested it with on macOS High Sierra 10.13.6 (17G65).

User uploaded file


This is the System Python 2.7.10. The Python-Objective-C bridge is available by default in Python when you import that appropriate Class library. Ideally the following code should be within a delegate that responds to events, but keeping it simple:

User uploaded file

Aug 24, 2018 12:33 PM in response to red_menace

Well, how do you make the loop looser then? I didn't know that there were different kinds of runloops. I tried the following code, but it did not solve the problem:



def temp23(str1):

return NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()



def temp22():

active_app_name = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()

print (active_app_name)

time.sleep(30)

print (temp23(active_app_name))

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

AppKit not dynamically sensing the Frontmost App

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.