Skip to content

Commit

Permalink
Infrastructure for passing layer shell config from python to glfw
Browse files Browse the repository at this point in the history
  • Loading branch information
kovidgoyal committed Mar 24, 2024
1 parent 217e37b commit 3a52e6b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 11 deletions.
13 changes: 12 additions & 1 deletion kitty/fast_data_types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@ from kitty.fonts import FontFeature
from kitty.fonts.render import FontObject
from kitty.marks import MarkerFunc
from kitty.options.types import Options
from kitty.types import SignalInfo
from kitty.types import LayerShellConfig, SignalInfo

# Constants {{{
GLFW_LAYER_SHELL_NONE: int
GLFW_LAYER_SHELL_PANEL: int
GLFW_LAYER_SHELL_BACKGROUND: int
GLFW_EDGE_TOP: int
GLFW_EDGE_BOTTOM: int
GLFW_EDGE_LEFT: int
GLFW_EDGE_RIGHT: int
GLFW_FOCUS_NOT_ALLOWED: int
GLFW_FOCUS_EXCLUSIVE: int
GLFW_FOCUS_ON_DEMAND: int
IMAGE_PLACEHOLDER_CHAR: int
GLFW_PRIMARY_SELECTION: int
GLFW_CLIPBOARD: int
Expand Down Expand Up @@ -508,6 +518,7 @@ def create_os_window(
x: Optional[int] = None,
y: Optional[int] = None,
disallow_override_title: bool = False,
layer_shell_config: Optional[LayerShellConfig] = None,
) -> int:
pass

Expand Down
36 changes: 28 additions & 8 deletions kitty/glfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1047,18 +1047,35 @@ native_window_handle(GLFWwindow *w) {
return Py_None;
}

static GLFWLayerShellConfig
translate_layer_shell_config(PyObject *p) {
GLFWLayerShellConfig ans = {0};
#define A(attr, type_check, convert) RAII_PyObject(attr, PyObject_GetAttrString(p, #attr)); if (attr == NULL) return ans; if (!type_check(attr)) { PyErr_SetString(PyExc_TypeError, #attr " not of the correct type"); return ans; }; ans.attr = convert(attr);
A(output_name, PyUnicode_Check, PyUnicode_AsUTF8);
A(type, PyLong_Check, PyLong_AsLong);
A(edge, PyLong_Check, PyLong_AsLong);
A(focus_policy, PyLong_Check, PyLong_AsLong);
#undef A
return ans;
}

static PyObject*
create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
int x = INT_MIN, y = INT_MIN, window_state = WINDOW_NORMAL, disallow_override_title = 0;
char *title, *wm_class_class, *wm_class_name;
PyObject *optional_window_state = NULL, *load_programs = NULL, *get_window_size, *pre_show_callback, *optional_x = NULL, *optional_y = NULL;
static const char* kwlist[] = {"get_window_size", "pre_show_callback", "title", "wm_class_name", "wm_class_class", "window_state", "load_programs", "x", "y", "disallow_override_title", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kw, "OOsss|OOOOp", (char**)kwlist,
&get_window_size, &pre_show_callback, &title, &wm_class_name, &wm_class_class, &optional_window_state, &load_programs, &optional_x, &optional_y, &disallow_override_title)) return NULL;
if (optional_window_state && optional_window_state != Py_None) { if (!PyLong_Check(optional_window_state)) { PyErr_SetString(PyExc_TypeError, "window_state must be an int"); return NULL; } window_state = (int) PyLong_AsLong(optional_window_state); }
if (optional_x && optional_x != Py_None) { if (!PyLong_Check(optional_x)) { PyErr_SetString(PyExc_TypeError, "x must be an int"); return NULL;} x = (int)PyLong_AsLong(optional_x); }
if (optional_y && optional_y != Py_None) { if (!PyLong_Check(optional_y)) { PyErr_SetString(PyExc_TypeError, "y must be an int"); return NULL;} y = (int)PyLong_AsLong(optional_y); }
if (window_state < WINDOW_NORMAL || window_state > WINDOW_MINIMIZED) window_state = WINDOW_NORMAL;
PyObject *optional_window_state = NULL, *load_programs = NULL, *get_window_size, *pre_show_callback, *optional_x = NULL, *optional_y = NULL, *layer_shell_config = NULL;
static const char* kwlist[] = {"get_window_size", "pre_show_callback", "title", "wm_class_name", "wm_class_class", "window_state", "load_programs", "x", "y", "disallow_override_title", "layer_shell_config", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kw, "OOsss|OOOOpO", (char**)kwlist,
&get_window_size, &pre_show_callback, &title, &wm_class_name, &wm_class_class, &optional_window_state, &load_programs, &optional_x, &optional_y, &disallow_override_title, &layer_shell_config)) return NULL;
if (layer_shell_config && global_state.is_wayland) {
glfwWaylandSetupLayerShellForNextWindow(translate_layer_shell_config(layer_shell_config));
} else {
if (optional_window_state && optional_window_state != Py_None) { if (!PyLong_Check(optional_window_state)) { PyErr_SetString(PyExc_TypeError, "window_state must be an int"); return NULL; } window_state = (int) PyLong_AsLong(optional_window_state); }
if (optional_x && optional_x != Py_None) { if (!PyLong_Check(optional_x)) { PyErr_SetString(PyExc_TypeError, "x must be an int"); return NULL;} x = (int)PyLong_AsLong(optional_x); }
if (optional_y && optional_y != Py_None) { if (!PyLong_Check(optional_y)) { PyErr_SetString(PyExc_TypeError, "y must be an int"); return NULL;} y = (int)PyLong_AsLong(optional_y); }
if (window_state < WINDOW_NORMAL || window_state > WINDOW_MINIMIZED) window_state = WINDOW_NORMAL;
}
if (PyErr_Occurred()) return NULL;

static bool is_first_window = true;
if (is_first_window) {
Expand Down Expand Up @@ -2183,6 +2200,9 @@ init_glfw(PyObject *m) {
ADDC(GLFW_REPEAT);
ADDC(true); ADDC(false);
ADDC(GLFW_PRIMARY_SELECTION); ADDC(GLFW_CLIPBOARD);
ADDC(GLFW_LAYER_SHELL_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND);
ADDC(GLFW_FOCUS_NOT_ALLOWED); ADDC(GLFW_FOCUS_EXCLUSIVE); ADDC(GLFW_FOCUS_ON_DEMAND);
ADDC(GLFW_EDGE_TOP); ADDC(GLFW_EDGE_BOTTOM); ADDC(GLFW_EDGE_LEFT); ADDC(GLFW_EDGE_RIGHT);

/* start glfw functional keys (auto generated by gen-key-constants.py do not edit) */
ADDC(GLFW_FKEY_ESCAPE);
Expand Down
5 changes: 3 additions & 2 deletions kitty/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
from .os_window_size import initial_window_size_func
from .session import create_sessions, get_os_window_sizing_data
from .shaders import CompileError, load_shader_programs
from .types import SingleInstanceData
from .types import LayerShellConfig, SingleInstanceData
from .utils import (
cleanup_ssh_control_masters,
detach,
Expand Down Expand Up @@ -269,7 +269,7 @@ def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ())
run_app.initial_window_size_func(get_os_window_sizing_data(opts, startup_sessions[0] if startup_sessions else None), cached_values),
pre_show_callback,
args.title or appname, args.name or args.cls or appname,
wincls, wstate, load_all_shaders, disallow_override_title=bool(args.title))
wincls, wstate, load_all_shaders, disallow_override_title=bool(args.title), layer_shell_config=run_app.layer_shell_config)
boss = Boss(opts, args, cached_values, global_shortcuts)
boss.start(window_id, startup_sessions)
if bad_lines or boss.misc_config_errors:
Expand All @@ -286,6 +286,7 @@ class AppRunner:
def __init__(self) -> None:
self.cached_values_name = 'main'
self.first_window_callback = lambda window_handle: None
self.layer_shell_config: Optional[LayerShellConfig] = None
self.initial_window_size_func = initial_window_size_func

def __call__(self, opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None:
Expand Down
7 changes: 7 additions & 0 deletions kitty/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ class SignalInfo(NamedTuple):
sival_ptr: int


class LayerShellConfig(NamedTuple):
type: int = 0
edge: int = 0
focus_policy: int = 0
output_name: Optional[str] = None


def mod_to_names(mods: int, has_kitty_mod: bool = False, kitty_mod: int = 0) -> Iterator[str]:
if has_kitty_mod:
mods &= ~kitty_mod
Expand Down

0 comments on commit 3a52e6b

Please sign in to comment.