Transparent click-through web browser overlay ("HUD") over your whole desktop, using WebKit.
If you know web development, you can use Hudkit to make the coolest statusbar in existence, or SVG desktop fireworks, or whatever else you can think of using a fullscreen transparent web view for.
- Works with multiple monitors, and connecting/disconnecting them.
- Has a JavaScript API, so scripts on the page can query monitor layout and change which areas of the overlay are clickable, for example.
- Small executable. Uses native GTK and WebKit libraries.
- Supports modern web APIs like WebSockets, WebAudio, WebGL, etc.
Platforms: ✔️ Linux (X11) ✔️❔ Linux (Wayland) 🚫 Windows 🚫 OS X
cd /tmp
git clone https://github.com/anko/hudkit.git
cd hudkit
make
./example/run.sh
If make
complains, check dependencies.
You should see something like this, if you have 2 monitors:
The code for what you see there is in the example/
directory. It
contains some explanatory comments, so it might make a good starting point for
your experiments. If you come up with a (fairly compact) example of your own,
please PR.
To open Web Inspector targeting the example page, ./example/run.sh --inspect
.
USAGE: ./hudkit <URL> [--help] [--webkit-settings option1=value1,...]
<URL>
Universal Resource Locator to be loaded on the overlay web view.
For example, to load a local file, you'd pass something like:
file:///home/mary/test.html
or to load from a local web server at port 4000:
http://localhost:4000
--inspect
Open the Web Inspector (dev tools) on start.
--webkit-settings <settings>
The <settings> should be a comma-separated list of settings.
Boolean settings can look like
option-name
option-name=TRUE
option-name=FALSE
String, integer, and enum options look like
option-name=foo
option-name=42
To see settings available on your system's WebKit version, their
valid values, and default values, pass '--webkit-settings help'.
To see explanations of the settings, see
https://webkitgtk.org/reference/webkit2gtk/stable/WebKitSettings.html
--help
Print this help text, then exit.
All of the standard GTK debug options and env variables are also
supported. You probably won't need them, but you can find a list here:
https://developer.gnome.org/gtk3/stable/gtk-running.html
JavaScript on the web page context has a Hudkit
object, with these properties:
Return: an Array of {name, x, y, width, height}
objects, representing your
monitors' device names and dimensions.
Example:
const monitors = await Hudkit.getMonitorLayout()
monitors.forEach((m) => {
console.log(`${m.name} pos:${m.x},${m.y} size:${m.width},${m.height}`)
})
Registers the given listener
function to be called on events by the string
name eventName
.
Currently listenable events:
-
monitors-changed
: fired when a monitor is logically connected or disconnected, such as throughxrandr
.No arguments are passed to the
listener
. CallHudkit.getMonitorLayout
to get the updated layout. -
composited-changed
: fired when the ability of your desktop environment to render transparency changes; typically when your compositor is killed or restarted.The main reason this exists is so if you accidentally kill your compositor, you won't be stuck with the now fully opaque overlay window blocking your whole desktop, as long as your page listens for this event and calls
window.close()
in response.Arguments passed to listener:
haveTransparency
(Boolean). True if compositing is now supported, false otherwise.
De-registers the given listener
from the given eventName
, so it will no
longer be called.
Sets which areas of the overlay window are clickable. By default, it is not clickable. The given area replaces the previous.
Parameters:
-
rectangles
: Array of objects with propertiesx
,y
,width
, andheight
. Other properties are ignored, and missing properties are treated as 0. Can be an empty Array, to make everything non-clickable.The area of the desktop represented by the union of the given rectangles become input-opaque (able to receive mouse events). All other areas become input-transparent.
Return: undefined
Example:
// Make a tall narrow strip of the overlay window clickable, in the top left
// corner of the screen. The dimensions are in pixels.
Hudkit.setClickableAreas([
{ x: 0, y: 0, width: 200, height: 1000 }
], err => console.error(err))
Notes:
-
If the Web Inspector is attached to the overlay window, the area it occupies is automatically kept clickable, independently of calls to this function.
-
When monitors are connected or disconnected, your clickable areas are reset to nothing being clickable, because their positioning would be unpredictable. Subscribe to the
'monitors-changed'
event (Hudkit.on('monitors-changed', () => { ... })
) and update your clickable areas accordingly!
Opens the Web Inspector (also known as Developer Tools), for debugging the page loaded in the web view.
Parameters:
attached
: Boolean. Iftrue
, starts the inspector attached to the overlay window. Iffalse
, start the inspector in its own window. (Optional. Default:false
.)
Return: undefined
ℹ️ You can also start the inspector with the --inspect
flag. That's usually better, because it works even if your JS crashes before
calling this function.
window.close
exits Hudkit.
In the root directory of this project,
make
If you're missing any dependencies, the error should tell you which.
You'll need—
-
Standard C compilation tools:
make
,pkg-config
, and any C compiler of your choice (gcc
orclang
, probably).Any Linux distro has these; many have them installed by default. If not, consult your distro's documentation on how to install them. (Many distros have a single package containing all the C tools, for convenience, like Arch's
base-devel
package.) -
GTK 3, and a corresponding webkit2gtk.
On Arch, the packages are called
gtk3
andwebkit2gtk
.On Void, they are
gtk+3-devel
andwebkit2gtk-devel
.On Ubuntu, they are
libgtk-3-dev
andlibwebkit2gtk-4.0-devel
.On Mint, they are
libgtk-3-dev
andlibwebkit2gtk-4.0
.If you build on another distro, I'm interested in how it went.
Probably. Report them.
Is it safe to direct Hudkit at some random untrusted web page on the internet?
No. Hudkit is built on a web browser engine, but is not intended for use as a
general-purpose web browser. The window.Hudkit
object and other background
stuff are exposed to every page Hudkit loads. Although I've tried my best to
mitigate possible attacks, the API simply is not designed to be exposed to the
full badness of the wider internet.
Please point Hudkit only at a locally hosted web pages, unless you really know what you're doing.
How can I ensure my HUD doesn't accidentally load remote resources?
Define a Content-Security-Policy (CSP), like you'd do when developing any other web page. Hudkit supports those through WebKit.
I recommend the following: Add this meta tag inside your document's <head>
:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'">
This makes that page only able to load resources from the same host it was
loaded from (your local computer). All requests to anywhere else are blocked.
The 'unsafe-inline'
part allows inline <script>
and <style>
tags, which
are innocuous if you're never loading remote resources anyway.
You can test this by e.g. adding a <img src="http://example.com/">
tag to
your page. You'll see a log entry like this when it gets blocked:
CONSOLE SECURITY ERROR Refused to load http://example.com/ because it appears
in neither the img-src directive nor the default-src directive of the Content
Security Policy.
For further documentation on CSP, consult MDN Web Docs or content-security-policy.com.
Hudkit says my screen doesn't support transparency. What does this mean?
You're probably running a plain window manager (like i3, XMonad, or awesomewm), which doesn't have a built-in compositor. So you'll need to install and run a standalone compositor. I recommend compton, or picom.
I can't type anything into the Web Inspector while it's attached to the overlay window!
Yep, it's a known problem. You can work around it by detaching the web inspector into its own window, with one of the buttons in the top-left corner. It works normally when detached.
This bug is hard to fix for complex technical reasons: In short, we have to set X11's override-redirect flag on the overlay window, to guarantee that window managers cannot reposition it, reparent it, or otherwise mess with it. A side-effect of doing this is that the window does cannot receive input focus, which is fine for mouse events (since they aren't dependent on input focus), but it means no keyboard events. Unless you grab the keyboard device, which has its own problems.
My currently running Hudkit instance's page is in a weird state that I want to debug, but I forgot to pass the
--inspect
flag, and restarting it would lose its current state. What do?
You can send the Hudkit process a SIGUSR1
signal to open the Web Inspector.
For example, killall hudkit --signal SIGUSR1
.
Why am I getting a
SyntaxError
when I try toawait
a Hudkit function?
Probably because you're trying to use await
at the top-level of your
JavaScript file. This wart in the JavaScript standard is unfortunate, and the
wording of WebKit's error message for it even more so.
The fix is to create an async function at the top-level, and immediately call it, doing all of your async stuff inside it:
(async function () {
// You can use `await` here
})()
This will improve in the near future: There is a TC39 proposal for top-level await, which is backed by WebKit developers, and implementation is in progress.
Why is Xvfb complaining about extension "GLX" missing on display ":99" if I run the automated test?
Probably because you're running an Nvidia proprietary driver which are kind of
garbage. The test starts a
background instance of X11 so your desktop's settings don't interfere with it,
but inside that context OpenGL is randomly bricked on some versions of the
proprietary NV driver, and on some versions it works. The actual program
should work just fine either way though. Try the example/
.
-
Electron. I've heard it's possible to make Electron click-through and fullscreen. I have not gotten it to work, but maybe you can? Let me know if you do.
Possible starting point: Start
electron
with--enable-transparent-visuals --disable-gpu
. Callwin.setIgnoreMouseEvents
, set all the possible "please dear WM, do not touch this window"-flags, call thescreen
API for monitor arrangements and position your window accordingly. Sacrifice 55 paperclips to Eris of Discordia, kneel and pray.
- dnode makes it possible to make remote procedure calls from JS in the web page to JS on a web server.
- SockJS lets is a simple abstraction over WebSockets, for transferring data otherwise.
- D3 is a great data visualisation library.
xkbcat
can capture keystrokes everywhere in X11, for making a keyboard visualiser for livestreaming, or for triggering eye candy.sxhkd
is a fairly minimal X11 keyboard shortcut daemon. Can use it to run arbitrary commands in response to key combinations, such as throwing data into a named pipe read by a locally running web server that's in contact with hudkit by WebSocket.mpv
with the--input-ipc-server
flag can be queried for the currently playing music track. Various other music players can do this too if you google around.sensors
can show hardware temperatures and fan data.
ISC.