mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 08:26:56 +00:00
kitty can finally natively implement a quake like terminal dropdown
Currently Wayland (except for GNOME as usual) only.
This commit is contained in:
parent
9b5d5bf678
commit
85d58de035
7 changed files with 100 additions and 33 deletions
|
|
@ -97,6 +97,8 @@ Detailed list of changes
|
|||
0.42.0 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- The panel kitten can now be used to :ref:`quake`
|
||||
|
||||
- **Behavior change**: Now kitty does full grapheme segmentation following the
|
||||
Unicode 16 spec when splitting text into cells (:iss:`8533`)
|
||||
|
||||
|
|
|
|||
|
|
@ -62,4 +62,31 @@ panels and desktop components:
|
|||
* `pawbar <https://github.com/codelif/pawbar>`__
|
||||
|
||||
|
||||
.. _quake:
|
||||
|
||||
Make a Quake like quick access terminal
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. versionadded:: 0.42.0
|
||||
Support for quake mode, works only on Wayland, except for GNOME.
|
||||
|
||||
This kitten can be used to make a quick access terminal, that appears and
|
||||
disappears at a key press. To do so use the following command::
|
||||
|
||||
kitty +kitten panel --edge=top --layer=overlay --lines=15 \
|
||||
--focus-policy=exclusive --exclusive-zone=0 --override-exclusive-zone \
|
||||
-o background_opacity=0.8 --toggle-visibility --single-instance \
|
||||
--instance-group=quake kitten run-shell
|
||||
|
||||
Run this command in a terminal, and a quick access kitty panel will show up at
|
||||
the top of your screen. Run it again, and the panel will be hidden.
|
||||
|
||||
Simply bind this command to some key press in your window manager or desktop
|
||||
environment settings and then you have a quick access terminal at a single key press.
|
||||
You can use the various panel options to configure the size, appearance and
|
||||
position of the quick access panel. In particular, the :option:`kitty +kitten panel --config` and
|
||||
:option:`kitty +kitten panel --override` options can be used to theme the terminal appropriately,
|
||||
making it look different from regular kitty terminal instances.
|
||||
|
||||
|
||||
.. include:: ../generated/cli-kitten-panel.rst
|
||||
|
|
|
|||
59
glfw/wl_window.c
vendored
59
glfw/wl_window.c
vendored
|
|
@ -1341,6 +1341,26 @@ struct wl_cursor* _glfwLoadCursor(GLFWCursorShape shape, struct wl_cursor_theme*
|
|||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool
|
||||
attach_opengl_context_to_window(_GLFWwindow *window, const _GLFWctxconfig *ctxconfig, const _GLFWfbconfig *fbconfig) {
|
||||
if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
|
||||
ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitEGL())
|
||||
return false;
|
||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||
return false;
|
||||
}
|
||||
else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitOSMesa())
|
||||
return false;
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
|
|
@ -1383,24 +1403,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||
// and only then create the OpenGL context.
|
||||
if (window->wl.visible) loop_till_window_fully_created(window);
|
||||
debug("Creating OpenGL context and attaching it to window\n");
|
||||
if (ctxconfig->client != GLFW_NO_API)
|
||||
{
|
||||
if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
|
||||
ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitEGL())
|
||||
return false;
|
||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||
return false;
|
||||
}
|
||||
else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitOSMesa())
|
||||
return false;
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (ctxconfig->client != GLFW_NO_API) attach_opengl_context_to_window(window, ctxconfig, fbconfig);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1682,23 +1685,29 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
|||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (!window->wl.visible) {
|
||||
create_window_desktop_surface(window);
|
||||
if (!is_layer_shell(window)) create_window_desktop_surface(window);
|
||||
window->wl.visible = true;
|
||||
wl_surface_commit(window->wl.surface);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
{
|
||||
xdg_toplevel_destroy(window->wl.xdg.toplevel);
|
||||
xdg_surface_destroy(window->wl.xdg.surface);
|
||||
if (!window->wl.visible) return;
|
||||
if (is_layer_shell(window)) {
|
||||
wl_surface_attach(window->wl.surface, NULL, 0, 0);
|
||||
} else {
|
||||
if (window->wl.xdg.toplevel) {
|
||||
xdg_toplevel_destroy(window->wl.xdg.toplevel);
|
||||
xdg_surface_destroy(window->wl.xdg.surface);
|
||||
}
|
||||
window->wl.xdg.toplevel = NULL;
|
||||
window->wl.xdg.surface = NULL;
|
||||
window->wl.once.surface_configured = false;
|
||||
window->swaps_disallowed = true;
|
||||
}
|
||||
window->wl.once.surface_configured = false;
|
||||
window->swaps_disallowed = true;
|
||||
window->wl.visible = false;
|
||||
wl_surface_commit(window->wl.surface);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from kitty.fast_data_types import (
|
|||
GLFW_LAYER_SHELL_TOP,
|
||||
glfw_primary_monitor_size,
|
||||
make_x11_window_a_dock_window,
|
||||
toggle_os_window_visibility,
|
||||
)
|
||||
from kitty.os_window_size import WindowSizeData, edge_spacing
|
||||
from kitty.types import LayerShellConfig
|
||||
|
|
@ -161,6 +162,12 @@ panel invocations with the same :option:`--instance-group` will result
|
|||
in new panels being created in the first panel instance within that group.
|
||||
|
||||
|
||||
--toggle-visibility
|
||||
type=bool-set
|
||||
When set and using :option:`--single-instance` will toggle the visibility of the
|
||||
existing panel rather than creating a new one.
|
||||
|
||||
|
||||
--debug-rendering
|
||||
type=bool-set
|
||||
For internal debugging use.
|
||||
|
|
@ -265,10 +272,12 @@ def dual_distance(spec: str, min_cell_value_if_no_pixels: int = 0) -> tuple[int,
|
|||
|
||||
|
||||
def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig:
|
||||
ltype = {'background': GLFW_LAYER_SHELL_BACKGROUND,
|
||||
'bottom': GLFW_LAYER_SHELL_PANEL,
|
||||
'top': GLFW_LAYER_SHELL_TOP,
|
||||
'overlay': GLFW_LAYER_SHELL_OVERLAY}.get(opts.layer, GLFW_LAYER_SHELL_PANEL)
|
||||
ltype = {
|
||||
'background': GLFW_LAYER_SHELL_BACKGROUND,
|
||||
'bottom': GLFW_LAYER_SHELL_PANEL,
|
||||
'top': GLFW_LAYER_SHELL_TOP,
|
||||
'overlay': GLFW_LAYER_SHELL_OVERLAY
|
||||
}.get(opts.layer, GLFW_LAYER_SHELL_PANEL)
|
||||
ltype = GLFW_LAYER_SHELL_BACKGROUND if opts.edge == 'background' else ltype
|
||||
edge = {
|
||||
'top': GLFW_EDGE_TOP, 'bottom': GLFW_EDGE_BOTTOM, 'left': GLFW_EDGE_LEFT, 'right': GLFW_EDGE_RIGHT, 'center': GLFW_EDGE_CENTER, 'none': GLFW_EDGE_NONE
|
||||
|
|
@ -294,6 +303,10 @@ def layer_shell_config(opts: PanelCLIOptions) -> LayerShellConfig:
|
|||
def handle_single_instance_command(boss: BossType, sys_args: Sequence[str], environ: Mapping[str, str], notify_on_os_window_death: str | None = '') -> None:
|
||||
from kitty.tabs import SpecialWindow
|
||||
args, items = parse_panel_args(list(sys_args[1:]))
|
||||
if args.toggle_visibility and boss.os_window_map:
|
||||
for os_window_id in boss.os_window_map:
|
||||
toggle_os_window_visibility(os_window_id)
|
||||
return
|
||||
items = items or [kitten_exe(), 'run-shell']
|
||||
lsc = layer_shell_config(args)
|
||||
os_window_id = boss.add_os_panel(lsc, args.cls, args.name)
|
||||
|
|
|
|||
|
|
@ -1703,6 +1703,7 @@ def set_clipboard_data_types(ct: int, mime_types: Tuple[str, ...]) -> None: ...
|
|||
def get_clipboard_mime(ct: int, mime: Optional[str], callback: Callable[[bytes], None]) -> None: ...
|
||||
def run_with_activation_token(func: Callable[[str], None]) -> bool: ...
|
||||
def make_x11_window_a_dock_window(x11_window_id: int, strut: Tuple[int, int, int, int, int, int, int, int, int, int, int, int]) -> None: ...
|
||||
def toggle_os_window_visibility(os_window_id: int) -> bool: ...
|
||||
def wrapped_kitten_names() -> List[str]: ...
|
||||
def expand_ansi_c_escapes(test: str) -> str: ...
|
||||
def update_tab_bar_edge_colors(os_window_id: int) -> bool: ...
|
||||
|
|
|
|||
11
kitty/glfw.c
11
kitty/glfw.c
|
|
@ -2421,12 +2421,23 @@ is_layer_shell_supported(PyObject *self UNUSED, PyObject *args UNUSED) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
toggle_os_window_visibility(PyObject *self UNUSED, PyObject *wid) {
|
||||
if (!PyLong_Check(wid)) { PyErr_SetString(PyExc_TypeError, "os_window_id must be a int"); return NULL; }
|
||||
id_type id = PyLong_AsUnsignedLongLong(wid);
|
||||
OSWindow *w = os_window_for_id(id);
|
||||
if (!w || !w->handle) Py_RETURN_FALSE;
|
||||
if (glfwGetWindowAttrib(w->handle, GLFW_VISIBLE)) glfwHideWindow(w->handle);
|
||||
else glfwShowWindow(w->handle);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
// Boilerplate {{{
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
METHODB(set_custom_cursor, METH_VARARGS),
|
||||
METHODB(is_css_pointer_name_valid, METH_O),
|
||||
METHODB(toggle_os_window_visibility, METH_O),
|
||||
METHODB(pointer_name_to_css_name, METH_O),
|
||||
{"create_os_window", (PyCFunction)(void (*) (void))(create_os_window), METH_VARARGS | METH_KEYWORDS, NULL},
|
||||
METHODB(set_default_window_icon, METH_VARARGS),
|
||||
|
|
|
|||
12
setup.py
12
setup.py
|
|
@ -1255,11 +1255,10 @@ def build_static_binaries(args: Options, launcher_dir: str) -> None:
|
|||
build_static_kittens(args, launcher_dir, args.dir_for_static_binaries, for_platform=(os_, arch))
|
||||
|
||||
|
||||
@lru_cache(2)
|
||||
def kitty_cli_boolean_options() -> Tuple[str, ...]:
|
||||
with open(os.path.join(src_base, 'kitty/cli.py')) as f:
|
||||
def read_bool_options(path: str = 'kitty/cli.py') -> Tuple[str, ...]:
|
||||
with open(os.path.join(src_base, path)) as f:
|
||||
raw = f.read()
|
||||
m = re.search(r"^\s*OPTIONS = '''(.+?)'''", raw, flags=re.MULTILINE | re.DOTALL)
|
||||
m = re.search(r"^\s*OPTIONS = r?'''(.+?)'''", raw, flags=re.MULTILINE | re.DOTALL)
|
||||
assert m is not None
|
||||
ans: List[str] = []
|
||||
in_option: List[str] = []
|
||||
|
|
@ -1279,6 +1278,11 @@ def kitty_cli_boolean_options() -> Tuple[str, ...]:
|
|||
return tuple(ans)
|
||||
|
||||
|
||||
@lru_cache(2)
|
||||
def kitty_cli_boolean_options() -> Tuple[str, ...]:
|
||||
return tuple(set(read_bool_options()) | set(read_bool_options('kittens/panel/main.py')))
|
||||
|
||||
|
||||
def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 'source') -> None:
|
||||
werror = '' if args.ignore_compiler_warnings else '-pedantic-errors -Werror'
|
||||
cflags = f'-Wall {werror} -fpie'.split()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue