libnotify notifies the console, not $DISPLAY? - python

Please note: This is not the similar-sounding FAQ that involves a multi-headed display. This question is about two different computers.
If I log onto the console of two different computers, sitting-at.example.com and sshed-into.example.com, and then sitting in front of sitting-at.example.com I ssh (with X11 tunneling) into sshed-into.example.com...
If I do that and then run a little Python script that uses libnotify, the notification pops up on the console of sshed-into.example.com, not sitting-at.example.com. But I need the notification on sitting-at.example.com. It seems to me that would make more sense.
The result is I do not see the notification until I drive to the other location and log back into the console of sshed-into.example.com.
My code has a fallback to use a little GTK popup if libnotify raises an exception, but it doesn't kick in because as far as libnotify is concerned, things are working fine.
I could use the GTK popup all the time, like I used to, but I kinda like libnotify where feasible. For one thing, libnotify doesn't get lost if I click to a different virtual desktop or raise a window at an inopportune moment. The GTK popup does.
Is there a way of getting either a remote notification using libnotify, xor of getting an exception?
I've considered parsing $DISPLAY to see if it "looks local", but it seems like there should be a better way.
Thanks in advance!
PS: The code for the little script is opensource and can be found at http://stromberg.dnsalias.org/~strombrg/notify-when-up2.html

I wound up checking $DISPLAY, since the responses here weren't flowing thick and fast.
The function I used:
def is_local_display(regex=re.compile(r'^:0(\.[0-9]+)?$')):
"""Return True iff $DISPLAY points at a local display."""
if 'DISPLAY' not in os.environ:
return False
match = regex.match(os.environ['DISPLAY'])
return bool(match)

Related

Uncomplicated window interface for displaying status in python

I am trying to create a window in python where I will be displaying the status of a large system, a bunch of numbers or some LEDs. The idea is that the system sends messages to the display thread and the thread updates different parts of the window, like displaying a number or turning the color of a field. More importantly, the user interacts with system via command line of python interpreter, e.g. executing commands or updating variables.
One may simply suggest that I need to use one of the GUI packages, like pyqt or xwpython. But these modules are designed to build GUIs, that means they have plenty of resources to handle events moues clicks and so on, which I don't need. Also, these modules run a event loop which is a waste of resources as well as in many cases they block the python shell.
I tried to use pyqt without running the main loop. But when I do this windows thinks my application is not responding, and I get a bunch of problems. For example the close button on the window does not work, and any effort on closing it crashes my python session.
Any ideas on how I can implement my application?
Maybe you should consider to use the Apache's Superset dashboard.
Check this up:
https://superset.incubator.apache.org/installation.html
It makes amazing dashboards incredibly easy and useful.

"sh: Error: Can't open display" when I try to start a program from python

I have this really strange problem, basically I want to start xpdf (or Libreoffice) from my Python script, that is started by a systemd-service. When I start the script from terminal everything is working fine, but when I plug in my USB device that start the Service, I'll get this Error in my syslog:
sh[2321]: Error: Can't open Display
This error has something to do with X11, that's what my Google searches tell me.
So, my question is: How can I properly run a program like xpdf or libreoffice from Python?
import subprocess
subprocess.call("/usr/bin/xpdf")
This is it, basically. I know that it has something to do with the graphical enviroment, but I don't know how I can solve it.
The X display system has very good security to stop random local processes from just displaying stuff to the local screen (It was more a problem in the old days of expensive Sun and SGI systems where computer labs would often let users telnet to other boxes. Much fun could be had!).
If the user running the xpdf is the same user as the one who's logged into the X session, then you simply need to tell xpdf where to connect it's UI to. This is usually done by exporting DISPLAY=:0 to the environment, which means "connect to the first local screen". Most X programs also support -display :0 argument.
So do:
/usr/bin/xpdf -display :0
or:
DISPLAY=:0 /usr/bin/xpdf
It's very unlikely that you have more than one X session so :0 will work 99% of the time.
Since the issue is that xpdf isn't finding a display to connect to, we have two basic options: find and authenticate with an existing display, or make a new one. The latter is usually easier, something like:
xinit /usr/bin/xpdf -fullscreen $PDFFILE -- :2
This would start a new X display :2 running only xpdf, not even a window manager.
It finally worked, after trying and going crazy for around 2 weeks.
What worked was
os.system("DISPLAY=:0 /usr/bin/xpdf)
I know that subprocess.call is the better way to call the program, but it doesn't seem to work right now.
I'll try the way that Yann suggested later on, but for now I'm just overwhelmed with joy that it just works.
Thank you all for your help, I really appreciate it!

Mac Python Close Window

I was wondering if there was a way of watching for a window to open and when it does close it? I've got a very annoying VPN client on our Mac systems that is very verbose and gets really annoying. There's no configuration to change this, so I'm wondering if I could write a Python script that is always running and watching for the window to open and close it?
As far as I know, there's no global notification that gets generated every time a window is opened, and no standard notification that every app uses, and no other way to do this in general, short of (a) injecting code into the VPN client, (b) using deprecated functionality like CGRemoteOperation, or (c) reverse engineering undocumented Window Server functionality.
So, the simplest solution is to periodically poll for windows and close them, probably using UI scripting via ScriptingBridge, NSAppleScript (through pyobjc), or appscript.
For example:
se = appscript.app('SystemEvents')
while True:
try:
client = se.application_processes['Annoying VPN Client']
window = client.windows['Annoying Window']
close = window.buttons[1]
close.click()
except Exception as e:
print('Exception: {}'.format(e))
time.sleep(1)
If you're interested in the other options—which you won't be able to do from Python—let me know. If you're familiar with system-level C and ObjC programming, creating a SIMBL program that hooks into the ObjC runtime to insert your own delegate in front of the existing one and intercept the relevant messages isn't that hard.

Obscure, repeatable crashes in multi-threaded Python console application using tk

Using tk in my multi-threaded(*) console application causes it to crash without stacktrace, giving the message "Tcl_WaitForEvent: Notifier not initialized Abort trap".
The symptoms were that all my program's functions worked fine, until I brought up the tk window - then the very next operation would cause the crash.
Immediate searching found that Tkinter is not safe with respect to Python threads, so I made sure that I was not calling any Tk functions anywhere other than my main thread. The crashes continued.
I lost several hours because I believed that it was the specific command I was using that crashed the program - but eventually I realized that any keyboard input would crash the program.
After a lot of debugging, I finally boiled it down to a small program that demonstrates the issue, exposing what I believe is a bug or certainly a feature that needs documentation in the Tkinter library.
I was working on this posting I was debugging. I'm going to post it and answer my own question in the hopes that it will prevent the next person from wasting a day on it.
--
(* - Yes, it certainly needs to be multi-threaded. I have a thread for my socket connection, a thread that listens to a mic and finds levels, a thread to drive my serial port and more. In each case, the thing I'm reading on the thread naturally blocks most of the time.)
The solution!
The issue is that tk crashes if you read from Python's raw_input in a different thread from the tk thread!
A small program demonstrating the issue is here. If you run it, it gets keyboard input perfectly happily from the second thread - until you enter the command "tk" when it brings up an empty tk window. You can do whatever you like with that window - until you type in the console window and press return, when the whole program crashes.
Why am I reading from raw_input in a thread that isn't the main thread?
My program is a console application, but I'm controlling a lot of different parts, one of which is the pi3d OpenGL ES 2.0 graphics library which must be updated at or near the frame rate from the main Python thread.
How to work around it?
"Simple" enough - register for tk menu events and just get the keys directly! Except that's a crappy solution, because you have to emulate all those things that the console does for you already - deleting, left and right arrows and that sort of thing. But that's what I'll have to do.
Should the program become a fully-fledged tk application?
But I can't do that - the whole point of this program is that you can run it through a terminal window - often sshing into headless machines. I'm frankly more likely to make it a curses program!
The tk window is a minor part of the whole thing - just a window to show emulated lights when developing if you don't have the hardware hooked up (or don't want to keep flashing yourself in the face). I won't try to bring it up on headless machines, and that's fine.
Is this a bug?
I'm always loathe to attach such a label to software not my own, but I'm hard-pressed to come up with any other description. It causes a crash, and that crash produces no useful information of any type. I consider that Tkinter is somewhat lame for simply crashing when called from different threads, but at least this behavior is documented (if you dig down a little) - in this case, I'm calling a Python built-in, so I have no basis to expect that it will interact with this library at all, and there's no documentation of this problem.
Could there be a workaround?
I'm sort of hoping there will be a work-around - this one-page program was a single item on a long list of features has turned into a full-day head-scratching debugging session and I don't want to have to throw another day at least after this when none of this time is actually producing new features.
The best thing is if the tk team admitted this was a bug and came up with a fix. But I wouldn't expect that at my desktop before a year from now...
So perhaps the real best thing would be if there were some way to get tk to simply ignore the keyboard, and not crash. I did a tiny experiment with tk's "busy" but that didn't work and just doesn't seem to be the right sort of thing.
A little later, I'm now thinking about running the lighting as an independent program, a separate subprocess using Python's Subprocess library, and sending it text commands through stdin. This would be overkill if this were the only problem that was being solved, but in fact
Got it.
Replacing raw_input() with sys.stdin.readline() did the trick - at least in the demo (which I updated). Feel free to download this and experiment with it yourself!
I hope this saves someone else the time.
In my case (as mentioned in the comments under #Tom Swirly's answer) the solution was to switch to a non-interactive backend:
import matplotlib
matplotlib.use('Agg')

Finding when the ActiveApplication changes in OSX through Python

Is there a way to find when the activeApplication changes in OSX through Python and AppKit? I know how to find out launchedApplication and activeApplication ( please refer to my other question here: Finding the Current Active Window in Mac OS X using Python )
I've got an OS X app that does this by polling with an NSTimer. I tried searching for distributed notifications to see if I could find a better way to do it, but I couldn't see anything terribly useful.
I did get notifications when application were launched or quit. which is at least a little helpful. You can see the registration of these where my controller wakes up.
This application has been immensely helpful to me and even polling once a second uses nearly no CPU. If I could make it more event driven, I would, though. :)
I'm not aware of an 'official'/good way to do this, but one hackish way to go about this is to listen for any distributed notifications and see which ones are always fired when the frontmost app changes, so you can listen for that one:
You can set something like this up:
def awakeFromNib(self):
NSDistributedNotificationCenter.defaultCenter().addObserver_selector_name_object_(
self, 'someNotification:', None, None)
def someNotification_(self, notification):
NSLog(notification.name())
After you've found a notification that always fires when apps are switched, you can replace the first 'None' in the addObserver_etc_ call with the name of that notification and check for the frontmost app in your 'someNotification_' method.
In my case I noticed that the 'AppleSelectedInputSourcesChangedNotification' fired everytime I switched apps, so I would listen to that..
Keep in mind that this can break any moment and you'll prolly be checking for a change in the frontmost app more often than needed.
There must be a better way though.. hopefully :)

Categories