X11 - How to raise another application's window using Python - python

I'd like to be able to raise another application's Window using Python.
I did see this, which I suppose I could try:
X11: raise an existing window via command line?
However, I'd prefer to do it in Python if at all possible.

To activate another window, the right thing to do on the Xlib protocol layer is to send a _NET_ACTIVE_WINDOW message as described in the EWMH spec
http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html
This could be done with python-xlib (presumably) or with gdk_window_focus() on a foreign GdkWindow using GDK through pygtk
_NET_ACTIVE_WINDOW is superior to XRaiseWindow() and has been in all the important WMs for many many years.
You should avoid XSetInputFocus() which will cause problems (especially if you get the timestamp wrong). The issue is that the WM can't intercept the SetInputFocus() so it causes weird race conditions and UI inconsistencies.
Really only _NET_ACTIVE_WINDOW works properly, which is why it was invented, because the previous hacks were bad.
There is a library called libwnck that will let you activate windows (among other things) but unfortunately it adds quite a lot of overhead because it always tracks all open windows from any app, even if you don't need to do that. However if you want to track windows from other apps anyway, then libwnck has a function to activate those windows that does the right thing and would be a good choice.
The strictly correct approach is to check for EWMH _NET_ACTIVE_WINDOW support (EWMH documents how to do this) and fall back to XRaiseWindow if the WM doesn't have _NET_ACTIVE_WINDOW. However, since any WM that's been actively worked on in the last many years has EWMH, lots of people are lazy about the fallback for legacy WMs.

You need to use python-xlib and call .circulate(Xlib.X.RaiseLowest) on the window object (which can be identified in many, many different ways -- can't guess which one is appropriate for you from the zero amount of info about it in your Q;-). For a great example of using python-xlib, check out the tinywm window manager -- after the C version, the author gives a Python version that takes about 30 non-blank, non-comment lines (for a usable, if tiny, window manager...!-).

You can have a look at the python ewmh package. Documentation contains examples, but here is how you can achieve what you want:
from ewmh import EWMH
import random
ewmh = EWMH()
# get every displayed windows
wins = ewmh.getClientList()
# let's active one window randomly
ewmh.setActiveWindow(random.choice(wins))
# flush requests - that's actually do the real job
ewmh.display.flush()

Related

Python/PyQt/Qt QMenu QAction syntax

I have a syntax/understanding problem in an application using Python 3, PyQt5 and Qt5. I am unsure which of these is causing the problem.
I am charged with porting a GUI application which worked under Windows to Linux, with newer versions of libraries. I do not have access to the original running under Windows.
In several places I see:
menu = QMenu(self)
action = menu.addAction("Some string")
action.triggered[()].connect(self.handler)
I presume this used to work. I am porting to Python 3.5, PyQt 5.7 & Qt 5.7. I have reason to believe the code was written for earlier versions of each of these.
Executing it now generates a 'there is no matching overloaded signal' error, on the action.triggered[()] segment.
By guesswork and looking at a couple of examples I found somewhere, I have changed the last line to:
action.triggered.connect(self.handler)
and it seems to work now.
Could someone explain what the original triggered[()] syntax meant/worked, and which "product" the evident change was in --- it would be nice to be able to read about where this got changed? Is my replacement by simply triggered correct/same behaviour?
The relevant change happened in PyQt-5.3. It is not entirely safe to simply remove the old syntax, as this could easily create a subtle bug in both current and future code.
The issue is that certain signals like triggered will always send a default boolean value unless you take steps to eliminate it. Qt defines these signals like this:
triggered(bool checked = false)
PyQt previously implemented this as two overloads:
triggered(bool checked)
triggered()
and if you wanted to explicitly select the latter overload, you had to use the following slightly awkward sytax:
triggered[()].connect(slot)
But this is now no longer an option, as only the first overload is implemented. So to get exactly the same behaviour, it is necessary to either wrap the handler like this:
triggered.connect(lambda checked: slot())
or decorate it like this:
#QtCore.pyqtSlot()
def handleTriggered(self):
pass
Otherwise, it is quite easy to fall into a little trap. Imagine you have a method defined like this:
def frobnicate(self, foobar=True):
if foobar:
# do something nice
else:
# empty my home directory without prompting
Later on, you decide to hook this up to a button, like this:
self.button.clicked.connect(self.frobnicate)
Which all seems perfectly fine, until you find out that the clicked signal works just like triggered, and always sends False by default...
Of course, if you're absolutely certain that you will never connect slots which take arguments to signals like triggered and clicked, you could get away with connecting them all in the simplistic fashion shown above. But, really, that is just an accident waiting to happen...

How can I feed keys in to a terminal for unittesting purposes

I'm working on a plug-in for Vim, and I'd like to test that it behaves correctly, under start-up, when users edit files e.t.c.
To do this, I'd like to start a terminal, and feed keys in to it.
I'm thinking of doing it all from a python script. Is there a way to do this?
In pseudo-python it might look something like this:
#start a terminal. Here konsole
konsole = os.system('konsole --width=200 --height=150')
#start vim in that terminal
konsole.feed_keys("vim\n")
#run the vim function to be tested
konsole.feed_keys(":let my_list = MyVimFunction()\n")
#save the return value to the file system
konsole.feed_keys(":writefile(my_list, '/tmp/result')\n")
#load result into python
with open('/tmp/result', 'r') as myfile:
data = myfile.read()
#validate the result
assertEqual('expect result', data)
I think you should verify the core functionality of your plugin inside Vim, using unit tests. There's a wide variety of Vim plugins, but most provide some additional mappings or commands, to be invoked by the user, and they usually leave behind some side effects in the buffer, or output, or opened windows. That can be verified from inside Vim. There are a various approaches for that, mine is the runVimTests test framework; the plugin page has links to several alternatives.
With the core functionality thus covered, there's little left to test "interactively". (I mean stuff like forgotten debug output, too long execution times, display mess-ups.) Since you're usually a heavy user of Vim and your plugin yourself, that mostly covers it.
Of course, if your plugin embeds itself tightly into Vim (like an "IDE for XXX"; though this is usually frowned upon), you may consider some external test driver. Maybe others will contribute pointers to some general-purpose, terminal-driven test frameworks. I'm almost sure such exist.
While I'm maintaining a plugin that permits to run unit tests on VimL functions and feed the quickfix window with the results, I use another couple of tools to check the state of the buffer after some actions, and even run the thing from travis -> vimrunner+rspec, and VimFlavour for installing the dependencies. (I vaguely remember a Python alternative inspired by vimrunner)
It mostly works well. Alas it uses the client-server feature and :redir (instead of the more recent execute() function). Even with the use of :silent, :redir catches noise which it returns to the client. Thus sometimes I fight tests that fail for very odd reasons. I also find myself inserting some pseudo-pauses to be sure that Vim has finished to interpret what I've feed it.
You'll find example of use in some of my plugins. See for instance lh-brackets or lh-cpp tests (.travis.yml file + .rspec/ directory + Rakefile + Gemfile + some helpers from vim-UT)

Create playlist in iTunes with Python and Scripting Bridge

How do you create a playlist using Python and Scripting Bridge?
So far I have :
from Foundation import *
from ScriptingBridge import *
iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
newPlaylist = iTunes.iTunesPlaylist()
This obviously doesn't work.
I've seen things for Ruby and Objective C, but I don't really understand the language.
This is actually an example in the Scripting Bridge documentation. See Listing 2, "Adding an object to a scriptable application in PyObjC code":
from Foundation import *
from ScriptingBridge import *
iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
p = {'name':'Testing'}
playlist = iTunes.classForScriptingClass_("playlist").alloc().initWithProperties_(p)
iTunes.sources()[0].playlists().insertObject_atIndex_(playlist, 0)
If this doesn't make sense to you, there are a few different ugly things to explain…
First, SBApplication doesn't have any member iTunesPlaylist that's a nice subclass of SBObject. If you've generated static glue, ITApplication might have such a thing… but you don't want to use static glue. So, you have to dynamically create the class object iTunesPlaylist. There are a few different ways to do that, but the easy way (assuming you know it's called playlist in Applescript) is with classForScriptingClass_.
Next, ScriptingBridge isn't really a native Python bridge to AE; it's a Python bridge to the ObjC bridge to AE. So that iTunesPlaylist is actually a wrapped-up ObjC class, not Python class. That means you can't just instantiate it as iTunesPlaylist(), you have to say iTunesPlaylist.alloc().init().
Calling initWithProperties_(p) is a nice shortcut to initializing and setting properties in separate steps.
Finally, the way the AE object model works, you can't just "create an object", you have create an object at some location. ScriptingBridge tries to hide this from you, but it doesn't do a very good job. The playlist object you create doesn't actually represent anything in iTunes yet—in fact, if you look at its type or repr, you'll see that it's a "future iTunesPlaylist". You need to find an appropriate SBElementArray to insert it into, and then it will become a real playlist.
Not everything in ScriptingBridge is this horrible. But some of it is even worse. Just wait until you run into one of the areas where iTunes' scripting dictionary is wrong…
The iTunes AE interface itself is very nice, if you can avoid using ScriptingBridge. There are three ways around that, although they may not help you.
First, there's appscript (docs here). This is a different Python->AE bridge which is much better than SB. Here's what the same thing looks like (relying on the default that iTunes has a default location for playlists—at the end of the list of playlists in the first library source):
from appscript import *
iTunes = app('iTunes')
p = {'name':'Testing'}
playlist = iTunes.make(new=k.playlist, with_properties=p)
And if you can't figure out how to do what you want, but can find AppleScript sample code (e.g., at dougscripts), you can use the ASTranslate tool to write the equivalent appscript.
Unfortunately, the author of appscript has canceled the project. And with good reason—it relies on legacy APIs that Apple could remove in 10.9 (or cite to reject you from the App Store). At present, it still works fine, and a few people are keeping it alive at the github repo above, but one day, it will have to die for real. So, it may not be a good solution unless this is a personal, short-term, or learning project. (Also, specific to iTunes: 10.6.3 has a bug that affects appscript, but doesn't affect other bridges unless you're using them remotely. If you need to work with that version, see itunesterms for one solution.)
Of course there's always the obvious option: do it in AppleScript:
tell application "iTunes"
make new playlist with properties {name:"Testing4"}
end tell
The problem with AppleScript is that it's a horrible language for everything except talking AEOM, and its equivalent of Python's standard library is about 5% as deep and wide. But you can always use a two-language solution, in two ways. You can connect from AppleScript to other Cocoa code (e.g., Python with PyObjC) via ASOC. Or, alternatively, you can use NSAppleScript and friends to run scripts from PyObjC/etc.
The latter may be the most painful answer, but it has one huge advantage: If you use the new APIs in Mountain Lion, and your use cases fall within a certain narrow band, you can write a sandboxed app that scripts iTunes without needing a temporary exception entitlement, meaning you can sell it in the App Store.

Crossplatform method for inserting text into raw_input (to avoid readine) in Python

I have an application (CLI) which includes the feature of editing account information. It does this by asking a question and putting in the old value in the answer so that it is editable. Currently I'm using the readline module to do this. I'd like another way of doing the same thing that avoids this module (I want to allow the app to run with all features on Windows as well as GNU/Linux any operating system that python runs on).
I originally found the following code (I modified it a bit to fit into a function) at the following website but since that thread is 4 years old I figured I'd ask here. http://bytes.com/topic/python/answers/471407-default-editable-string-raw_input
import readline
def editInput(question, old_value):
readline.set_startup_hook(lambda: readline.insert_text(old_value))
try:
new_value = raw_input(question)
finally:
readline.set_startup_hook(None)
return new_value
editInput('What\'s the answer? ', '32')
UPDATE: I don't necessarily need an alternative for readline (such as PyReadline). I just need the same result. I updated the question to mention that I don't necessarily need it to run on Windows and GNU/Linux but on any OS supported by python. So basically, only use very basic functions (such as sys.stdin, etc.)
Line editing functionality is far from trivial to duplicate. For example, just a functionality such as "read the next keystroke without echoing" (even before you start intepreting the meaning of that keystroke in order to reposition the cursor and alter the on-screen appearance as well as the remembered contents of the text line being edited) cannot be done simply in a cross-platform way: you need msvcrt functionality on Windows and curses functionality on Unix-y systems -- and your demand that it works on any OS supported by Python looms huge, and impossible to satisfy.
You need to delimit very strictly the set of operating systems / platforms on which it must run, and the subset of line editing functionality it must absolutely provide, before an answer can be considered. If you just can't delimit those sets, then the answer is easy: what you're asking for is, in its excessive generality, simply impossible.
Why not use PyReadline? It is used by IPython for more or less the same functionality and is well supported by them.
Actually, scratch that. I have just tried it and it doesn't work. Likely, pyreadline doesn't support set_startup_hook.

IronPython - How to prevent CLR (and other modules) from being imported

I'm setting up a web application to use IronPython for scripting various user actions and I'll be exposing various business objects ready for accessing by the script. I want to make it impossible for the user to import the CLR or other assemblies in order to keep the script's capabilities simple and restricted to the functionality I expose in my business objects.
How do I prevent the CLR and other assemblies/modules from being imported?
This would prevent imports of both python modules and .Net objects so may not be what you want. (I'm relatively new to Python so I might be missing some things as well):
Setup the environment.
Import anything you need the user to have access to.
Either prepend to their script or execute:
__builtins__.__import__ = None #Stops imports working
reload = None #Stops reloading working (specifically stops them reloading builtins
#giving back an unbroken __import___!
then execute their script.
You'll have to search the script for the imports you don't want them to use, and reject the script in toto if it contains any of them.
Basically, just reject the script if it contains Assembly.Load, import or AddReference.
You might want to implement the protection using Microsoft's Code Access Security. I myself am not fully aware of its workings (or how to make it work with IPy), but its something which I feel you should consider.
There's a discussion thread on the IPy mailing list which you might want to look at. The question asked is similar to yours.
If you'd like to disable certain built-in modules I'd suggest filing a feature request over at ironpython.codeplex.com. This should be an easy enough thing to implement.
Otherwise you could simply look at either Importer.cs and disallow the import there or you could simply delete ClrModule.cs from IronPython and re-build (and potentially remove any references to it).
In case anyone comes across this thread from google still (like i did)
I managed to disable 'import clr' in python scripts by commenting out the line
//[assembly: PythonModule("clr", typeof(IronPython.Runtime.ClrModule))]
in ClrModule.cs, but i'm not convinced this is a full solution to preventing unwanted access, since you will still need to override things like the file builtin.

Categories