The name is a reference to devilspie, a similar utility. It is notable for the fact that the config is written in the Lisp dialect, despite this it has very limited capabilities. Especially for utilities like wmctl, etc.
You can do a lot more with the wnck library, and even more with gdk.
For global hotkeys, I used libkeybinder, I used to do this on "bare" xlib, but it's more convenient (and portable). However, xlib / xtest is also used - to emulate button presses. But these functions are optional.
I chose yaml as the config format. Older versions used a python config, but I decided that yaml is more convenient for end users. Moreover, you can embed code in python and sh into it.
I will not go into the details of the implementation. There is a lot of magic and metaprogramming, some of the code is generated.
I'd rather show an example of a config that uses some of the capabilities. By the way, new rules can be generated from the command line, it will take the name and class_group of the active window.
click_with_F1:
if:
key: F1
then:
click: 3
The simplest example. Pressing F1 will emulate a right mouse button click.
save_image:
if:
key: F2
class_group: Google-chrome
then:
- click: 3
- sleep: 0.1
- press: v
- enable: autosave
Pressing F2 will right-click, v (save as) and activate the autosave rule
# Would type "filename" and press alt+s to save when Save file dialog of chrome appears. But only after we pressed F2.
autosave:
if:
name: Save File
class_group: Google-chrome
enabled: false
then:
- press: f i l e n a m e Alt+S
# Disable autosaving every 2 secs.
timer_test:
if:
event: timer 2
then:
disable: autosave
When the Save File window appears, it will remember the file name and save it. This rule is disabled after 2 seconds. The file name will be auto-filled only when you press F2, and not for any windows.
print_debug:
if:
event: never
then:
debug:
win_changed:
if:
event: active_window_changed
then:
echo: "window changed {name} {class_group}"
switched_to_xterm:
if:
name:
contains: mc
class_group: XTerm
then:
- maximize:
- disable: win_changed
- trigger: print_debug
not_in_mc:
if:
or:
class_group:
ne: xterm
name:
contains_not: mc
then:
- sh: date
- py: from datetime import datetime;print(datetime.now())
print_debug trigger, . . wnck gdk. wnck. if , sh.
- . . , . , .
, , - mpv. , .
By the way. although there is a lot of magic in the code, I think it has a good architecture. I would like to hear criticism. But here the balance between the comprehensibility of the code and its versatility / compactness is important. The emphasis is on the latter.
The code is available on github and pypi. By the way. where else to place the program? I would like to convey it to desktop users. You might need to add a gui, but there are too many features. It is more convenient to just edit the config.