diff --git a/docs/index.rst b/docs/index.rst index c6292e7f7..955a6475c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -239,6 +239,10 @@ Some prominent kittens: filenames, words, lines, etc from the terminal screen. +:doc:`Panel ` + Draw a GPU accelerated dock panel on your desktop showing the output + from an arbitrary terminal program. + .. _sessions: Startup Sessions diff --git a/docs/kittens/panel.rst b/docs/kittens/panel.rst new file mode 100644 index 000000000..4d72e2a12 --- /dev/null +++ b/docs/kittens/panel.rst @@ -0,0 +1,37 @@ +Draw a GPU accelerated dock panel on your desktop +==================================================================================================== + +.. highlight:: sh + + +You can use this kitten to draw a GPU accelerated panel on the edge +of your screen, that shows the output from an arbitrary terminal program. + +It is useful for showing status information or notifications on your desktop +using terminal programs instead of GUI toolkits. + + +.. figure:: ../screenshots/panel.png + :alt: Screenshot, showing a sample panel + :align: center + :scale: 100% + + Screenshot, showing a sample panel + + +The screenshot above shows a sample panel that displays the current desktop and +window title as well as miscellaneous system information such as network +activity, CPU load, date/time, etc. + +.. note:: + + This kitten currently only works on X11 desktops + +Using this kitten is simple, for example:: + + kitty +kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s' + +This will show ``Hello, world.`` at the top edge of your screen for five +seconds. Here the terminal program we are running is ``sh`` with a script to +print out ``Hello, world!``. You can make the terminal program as complex as +you like, as demonstrated in the screenshot above. diff --git a/docs/screenshots/panel.png b/docs/screenshots/panel.png new file mode 100644 index 000000000..5326f10d0 Binary files /dev/null and b/docs/screenshots/panel.png differ diff --git a/kittens/panel/__init__.py b/kittens/panel/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kittens/panel/main.py b/kittens/panel/main.py new file mode 100644 index 000000000..b0640b83a --- /dev/null +++ b/kittens/panel/main.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2018, Kovid Goyal + +import subprocess +import sys + +from kitty.constants import is_macos, is_wayland +from kitty.cli import parse_args + + +OPTIONS = r''' +--lines +type=int +default=1 +The number of lines shown in the panel (the height of the panel). Applies to horizontal panels. + + +--columns +type=int +default=20 +The number of columns shown in the panel (the width of the panel). Applies to vertical panels. + + +--edge +choices=top,bottom,left,right +default=top +Which edge of the screen to place the panel on. Note that some window managers +(such as i3) do not support placing docked windows on the left and right edges. + + +--config -c +type=list +Path to config file to use for kitty when drawing the panel. + + +--override -o +type=list +Override individual kitty configuration options, can be specified multiple times. +Syntax: :italic:`name=value`. For example: :option:`kitty +kitten panel -o` font_size=20 +'''.format + + +args = None + + +def parse_panel_args(args): + msg = 'Use a command line program to draw a GPU accelerated panel on your X11 desktop' + return parse_args(args, OPTIONS, 'program-to-run', msg, 'panel') + + +def call_xprop(*cmd, silent=False): + cmd = ['xprop'] + list(cmd) + try: + cp = subprocess.run(cmd, stdout=subprocess.DEVNULL if silent else None) + except FileNotFoundError: + raise SystemExit('You must have the xprop program installed') + if cp.returncode != 0: + raise SystemExit(cp.returncode) + + +def create_strut( + win_id, + left=0, right=0, top=0, bottom=0, left_start_y=0, left_end_y=0, + right_start_y=0, right_end_y=0, top_start_x=0, top_end_x=0, + bottom_start_x=0, bottom_end_x=0 +): + call_xprop( + '-id', + str(int(win_id)), '-format', '_NET_WM_STRUT_PARTIAL', '32cccccccccccc', + '-set', '_NET_WM_STRUT_PARTIAL', + '{left},{right},{top},{bottom},' + '{left_start_y},{left_end_y},{right_start_y},{right_end_y},' + '{top_start_x},{top_end_x},{bottom_start_x},{bottom_end_x}'.format(**locals()) + ) + + +def create_top_strut(win_id, width, height): + create_strut(win_id, top=height, top_end_x=width) + + +def create_bottom_strut(win_id, width, height): + create_strut(win_id, bottom=height, bottom_end_x=width) + + +def create_left_strut(win_id, width, height): + create_strut(win_id, left=width, left_end_y=height) + + +def create_right_strut(win_id, width, height): + create_strut(win_id, right=width, right_end_y=height) + + +def setup_x11_window(win_id): + call_xprop( + '-id', str(win_id), '-format', '_NET_WM_WINDOW_TYPE', '32a', + '-set', '_NET_WM_WINDOW_TYPE', '_NET_WM_WINDOW_TYPE_DOCK' + ) + func = globals()['create_{}_strut'.format(args.edge)] + func(win_id, initial_window_size_func.width, initial_window_size_func.height) + + +def initial_window_size_func(opts, *a): + from kitty.fast_data_types import glfw_primary_monitor_size, set_smallest_allowed_resize + + def initial_window_size(cell_width, cell_height, dpi_x, dpi_y): + monitor_width, monitor_height = glfw_primary_monitor_size() + if args.edge in {'top', 'bottom'}: + h = initial_window_size_func.height = cell_height * args.lines + 1 + initial_window_size_func.width = monitor_width + set_smallest_allowed_resize(100, h) + else: + w = initial_window_size_func.width = cell_width * args.columns + 1 + initial_window_size_func.height = monitor_height + set_smallest_allowed_resize(w, 100) + return initial_window_size_func.width, initial_window_size_func.height + + return initial_window_size + + +def main(sys_args): + global args + if is_macos or is_wayland: + raise SystemExit('Currently the panel kitten is supported only on X11 desktops') + call_xprop('-version', silent=True) # ensure xprop is available + args, items = parse_panel_args(sys_args[1:]) + if not items: + raise SystemExit('You must specify the program to run') + sys.argv = ['kitty'] + if args.config: + sys.argv.append('--config={}'.format(args.config)) + for override in args.override: + sys.argv.append('--override={}'.format(override)) + sys.argv.extend(items) + from kitty.main import run_app, main + run_app.cached_values_name = 'panel' + run_app.first_window_callback = setup_x11_window + run_app.initial_window_size_func = initial_window_size_func + main() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/kittens/runner.py b/kittens/runner.py index f3490692b..e974be4f4 100644 --- a/kittens/runner.py +++ b/kittens/runner.py @@ -12,7 +12,7 @@ aliases = {'url_hints': 'hints'} def resolved_kitten(k): - return aliases.get(k, k) + return aliases.get(k, k).replace('-', '_') def import_kitten_main_module(config_dir, kitten):