Created
August 3, 2022 08:55
-
-
Save gandalf3/67285f8e4d5e7f740890889f230738a9 to your computer and use it in GitHub Desktop.
Minimal demo of a working passive keyboard grab in X11 from a kitten for kitty terminal emulator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import sys | |
from Xlib import X | |
from typing import List | |
from kitty.constants import is_macos | |
# Installation: place minimal_popup.py in your ~/.config/kitty | |
# Usage: kitty +kitten minimal_popup <command> | |
def setup_x11_window(win_id: int) -> None: | |
import ctypes | |
from kitty.fast_data_types import x11_display | |
X11 = ctypes.CDLL("libX11.so") | |
class Display(ctypes.Structure): | |
""" opaque struct """ | |
# The Pixmap, Colormap, and Cursor types in Xlib are all defined as "XID". | |
# If Xlib has been built with _XSERVER64 defined (see X.h +59), then XID is | |
# defined as "unsigned long" (which on a typical "64 bit" system is 8 | |
# bytes) | |
# Otherwise, XID is defined as a CARD32 (see Xmd.h +115) which, on a *non* | |
# "64 bit" system (one where an unsigned long is 4 bytes), is also defined | |
# as an unsigned long. All that to say, it *should* be safe to consider | |
# XID to be always an ulong except if we are using a 32 bit xserver in a 64 | |
# bit environment, such that ctypes defines c_ulong as 8 bytes but Xlib's | |
# ulong is 4. I'm not sure what a reliable way to detect that would be, so | |
# for now we let sleeping dragons lie~ | |
XID_type = ctypes.c_ulong | |
override_redirect_mask = ctypes.c_long(1<<9) | |
# Xlib.h +298 | |
class XSetWindowAttributes(ctypes.Structure): | |
_fields_ = [ | |
('background_pixmap', XID_type), #Pixmap | |
('background_pixel', ctypes.c_ulong), | |
('border_pixmap', XID_type), #Pixmap | |
('border_pixel', ctypes.c_ulong), | |
('bit_gravity', ctypes.c_int), | |
('win_gravity', ctypes.c_int), | |
('backing_store', ctypes.c_int), | |
('backing_planes', ctypes.c_ulong), | |
('backing_pixel', ctypes.c_ulong), | |
('save_under', ctypes.c_bool), | |
('event_mask', ctypes.c_long), | |
('do_not_propagate_mask', ctypes.c_long), | |
('override_redirect', ctypes.c_bool), | |
('colormap', XID_type), #Colormap | |
('cursor', XID_type), #Cursor | |
] | |
dpy = x11_display() | |
dpy = ctypes.cast(dpy, ctypes.POINTER(Display)) | |
X11.XMapWindow.restype = ctypes.c_int | |
window_attributes = XSetWindowAttributes() | |
window_attributes.override_redirect = True | |
X11.XChangeWindowAttributes(dpy, win_id, | |
override_redirect_mask, | |
ctypes.pointer(window_attributes) | |
) | |
X11.XMapWindow(dpy, win_id) | |
X11.XGrabKeyboard(dpy, win_id, False, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime) | |
def main(sys_args: List[str]) -> None: | |
global args | |
if is_macos or not os.environ.get('DISPLAY'): | |
raise SystemExit('Currently the popup kitten is supported only on X11 desktops') | |
items = sys_args[1:] | |
if not items: | |
raise SystemExit('You must specify the program to run') | |
sys.argv = ['kitty'] | |
sys.argv.extend(items) | |
from kitty.main import main as real_main, run_app | |
run_app.first_window_callback = setup_x11_window | |
real_main() | |
if __name__ == '__main__': | |
main(sys.argv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment