Only a compound can be beautiful, never anything devoid of parts; and only a whole;
the several parts will have beauty, not in themselves,
but only as working together to give a comely total.
Yet beauty in an aggregate demands beauty in details:
it cannot be constructed out of ugliness; its law must run throughout.
–Plotinus,First Ennead
Have you used Sublime Text's or Atom's "Command Palette"? It's a list of everything those editors can do that opens at the press of a key and finds the action you are looking for just by typing a few letters. It's raw power at your fingertips.
Plotinus brings that powerto every application on your system(that is, to those that use the GTK+ 3 toolkit). It automatically extracts all available commands by introspecting a running application, instantly adapting to UI changes and showing only relevant actions. Using Plotinus requiresno modificationsto the application itself!
Just pressCtrl+Shift+P(configurable) and you're in business – it feels so natural you'll soon wonder how you ever lived without it.
To build Plotinus from source, you need Git, CMake, Vala, and the GTK+ 3 development files. All of these are easily obtained on most modern Linux distributions:
sudo dnf install git cmake vala gtk3-devel
sudo apt-get install git cmake valac libgtk-3-dev
git clone https://github /p-e-w/plotinus.git
cd plotinus
mkdir build
cd build
cmake..
make
sudo make install
Because of the complexity and clumsiness surrounding Linux environment variables, Plotinus is currently not enabled automatically. The easiest way to enable Plotinus for all applications on the system is to add the line
GTK3_MODULES=[libpath]
to/etc/environment
,where[libpath]
is thefull, absolutepath oflibplotinus.so
,which can be found using the command
whereis -b libplotinus
Alternatively, you can try Plotinus with individual applications by running them with
GTK3_MODULES=[libpath] application
from a terminal.
Plotinus can be configured both globally and per application. Application settings take precedence over global settings. In the commands below,[application]
can be either
default
,in which case the setting is applied globally, or- the path of an application executable, without the leading slash and with all other slashes replaced by periods (e.g.
/usr/bin/gedit
->usr.bin.gedit
).
Note that the relevant path is the path of theprocess executable,which is not always identical to the executable being launched. For example, all GNOME JavaScript applications run the process/usr/bin/gjs
.
gsettings set com.worldwidemann.plotinus:/com/worldwidemann/plotinus/[application]/ enabled [true/false]
gsettings set com.worldwidemann.plotinus:/com/worldwidemann/plotinus/[application]/ hotkeys '[keys]'
[keys]
must be an array of strings in the format expected bygtk_accelerator_parse
,e.g.[ "<Primary><Shift>P", "<Primary>P" ]
.Each shortcut in the array opens the command palette.
gsettings set com.worldwidemann.plotinus:/com/worldwidemann/plotinus/[application]/ dbus-enabled [true/false]
See the following section for details.
Plotinus provides a simple but completeD-BusAPI for developers who want to use its functionality from their own software. The API consists of two methods, exposed on the session bus atcom.worldwidemann.plotinus
:
-
GetCommands(window_path) -> (bus_name, command_paths)
Takes the object path of a GTK+ window (which can e.g. be obtained from a Mutter window viameta_window_get_gtk_window_object_path
) and returns an array of object paths referencing commands extracted from that window, as well as the name of the bus on which they are registered.
The mechanism behind this method is somewhat similar toUbuntu's AppMenu Registrar,but more lightweight and compatible with Wayland. Window registrationmust be enabledbefore using this method. -
ShowCommandPalette(commands) -> (bus_name, command_palette_path)
Takes an array of commands (structs of the form(path, label, accelerators)
) and opens a command palette window displaying those commands. The returned object path references a control object registered on the returned bus name which provides signals on user interaction with the window.
Calls to these methods are processed by thePlotinus D-Bus service,which can be started with
plotinus
The following examples demonstrate how to use the D-Bus API from Python. They requirepydbusto be installed and the Plotinus D-Bus service to be running.
#!/usr/bin/env Python
importsys
frompydbusimportSessionBus
bus=SessionBus()
plotinus=bus.get("com.worldwidemann.plotinus")
bus_name,command_paths=plotinus.GetCommands(sys.argv[1])
commands=[bus.get(bus_name,command_path)forcommand_pathincommand_paths]
fori,commandinenumerate(commands):
print("[%d] %s -> %s"%(i,"->".join(command.Path),command.Label))
index=raw_input("Number of command to execute:")
ifindex:
commands[int(index)].Execute()
Before running this example, enable window registration with
gsettings set com.worldwidemann.plotinus:/com/worldwidemann/plotinus/default/ dbus-enabled true
Then, run an application (e.g. gedit) withPlotinus enabled.Now run the script with the window object path as an argument, i.e.
./application_remote_control.py /org/gnome/gedit/window/1
Based onthis Argos plugin,uses Plotinus' command palette to display a list of applications available on the system.
#!/usr/bin/env Python
importos,re
frompydbusimportSessionBus
fromgi.repositoryimportGLib,Gio
applications={}
forapp_infoinGio.AppInfo.get_all():
categories=app_info.get_categories()
ifcategoriesisNone:
continue
# Remove "%U" and "%F" placeholders
command_line=re.sub("%\\w ","",app_info.get_commandline()).strip()
app=(app_info.get_name(),command_line)
forcategoryincategories.split(";"):
ifcategorynotin["GNOME","GTK",""]:
ifcategorynotinapplications:
applications[category]=[]
applications[category].append(app)
break
commands=[]
command_lines=[]
forcategory,appsinsorted(applications.items()):
forappinsorted(apps):
commands.append(([category],app[0], []))
command_lines.append(app[1])
bus=SessionBus()
plotinus=bus.get("com.worldwidemann.plotinus")
bus_name,command_palette_path=plotinus.ShowCommandPalette(commands)
command_palette=bus.get(bus_name,command_palette_path)
loop=GLib.MainLoop()
defcommand_executed(index):
os.system(command_lines[index])
command_palette.CommandExecuted.connect(command_executed)
defclosed():
# Wait for CommandExecuted signal
GLib.timeout_add(500,loop.quit)
command_palette.Closed.connect(closed)
loop.run()
Documentation on GTK+ modules is essentially nonexisting. Withoutgtkparasiteandgnome-globalmenuto learn from, it would have been a lot harder to get this project off the ground.
The CMake modules are copied verbatim from Elementary'spantheon-installerrepository.
Vala is still the greatest thing ever to happen to Linux Desktop development.
Contributors are always welcome. However,please file an issue describing what you intend to add before opening a pull request,especiallyfor new features! I have a clear vision of what I want (and do not want) Plotinus to be, so discussing potential additions might help you avoid duplication and wasted work.
By contributing, you agree to release your changes under the same license as the rest of the project (see below).
Copyright © 2016-2017 Philipp Emanuel Weidmann (pew@worldwidemann)
Released under the terms of theGNU General Public License, version 3