diff --git a/kitty/boss.py b/kitty/boss.py index 250072e1a..0a773e634 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -85,6 +85,9 @@ from .fast_data_types import ( get_boss, get_options, get_os_window_size, + get_os_window_pos, + glfw_primary_monitor_size, + glfw_get_monitor_workarea, global_font_size, is_layer_shell_supported, last_focused_os_window_id, @@ -1864,6 +1867,10 @@ class Boss: for qt in q: windows += list(qt) active_window = self.active_window + x, y = get_os_window_pos(active_window.id) + monitorGeometryX, monitorGeometryY = glfw_primary_monitor_size() + self.cached_values['window-pos'] = x, y + self.cached_values['monitor-workarea'] = glfw_get_monitor_workarea() msg, num_active_windows = self.close_windows_with_confirmation_msg(windows, active_window) x = get_options().confirm_os_window_close[0] num = num_active_windows if x < 0 else len(windows) diff --git a/kitty/cli.py b/kitty/cli.py index 68f8d6b8e..666e07287 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -602,6 +602,7 @@ def apply_preparsed_cli_flags(preparsed_from_c: PreparsedCLIFlags, ans: Any, cre def parse_cmdline(oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str] | None = None) -> list[str]: + names_map = oc.names_map.copy() values_map = oc.values_map.copy() if 'help' not in names_map: diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 4741f2207..9ceb7f2f9 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -648,6 +648,9 @@ def get_options() -> Options: def glfw_primary_monitor_size() -> Tuple[int, int]: pass +def glfw_get_monitor_workarea() -> [Tuple[int, int, int, int]]: + pass + def set_default_window_icon(path: str) -> None: pass diff --git a/kitty/glfw.c b/kitty/glfw.c index 1f02d4f69..7f5a8d96e 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -2127,6 +2127,42 @@ primary_monitor_size(PYNOARG) { return Py_BuildValue("ii", mode->width, mode->height); } +static PyObject * +get_monitor_workarea(PYNOARG) +{ + int count = 0; + GLFWmonitor **monitors = glfwGetMonitors(&count); + if (count == 0) + { + PyErr_SetString(PyExc_ValueError, "Failed to retrieve monitors"); + } + + PyObject *result = PyList_New(count); + if (!result) + { + return NULL; + } + + for (int i = 0; i < count; i++) + { + int xpos, ypos, width, height; + GLFWmonitor *monitor = monitors[i]; + + glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &width, &height); + + PyObject *monitor_workarea = Py_BuildValue("iiii", xpos, ypos, width, height); + if (!monitor_workarea) + { + Py_DECREF(monitor_workarea); + return NULL; + } + + PyList_SET_ITEM(result, i, monitor_workarea); + } + + return result; +} + static PyObject* primary_monitor_content_scale(PYNOARG) { GLFWmonitor* monitor = glfwGetPrimaryMonitor(); @@ -2626,6 +2662,7 @@ static PyMethodDef module_methods[] = { {"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""}, {"glfw_get_system_color_theme", (PyCFunction)glfw_get_system_color_theme, METH_VARARGS, ""}, {"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""}, + {"glfw_get_monitor_workarea", (PyCFunction)get_monitor_workarea, METH_NOARGS, ""}, {"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/kitty/main.py b/kitty/main.py index 6624718d2..a26657898 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -40,6 +40,8 @@ from .fast_data_types import ( free_font_data, glfw_init, glfw_terminate, + glfw_primary_monitor_size, + glfw_get_monitor_workarea, is_layer_shell_supported, load_png_data, mask_kitty_signals_process_wide, @@ -241,12 +243,19 @@ def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = (), getattr(startup_sessions[0], 'os_window_state', None) if startup_sessions else None ) wstate = parse_os_window_state(window_state) if window_state is not None else None + posX, posY = None, None + if args.position: + monitor_workarea = glfw_get_monitor_workarea() + cached_workarea = cached_values.get('monitor-workarea', None) + if cached_workarea and len(monitor_workarea) == len(cached_workarea): + if all([tuple(cached_workarea[i]) == monitor_workarea[i] for i in range(len(cached_workarea))]): + posX, posY = cached_values.get('window-pos', (None, None)) with startup_notification_handler(extra_callback=run_app.first_window_callback) as pre_show_callback: window_id = create_os_window( 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, winname, - wincls, wstate, load_all_shaders, disallow_override_title=bool(args.title), layer_shell_config=run_app.layer_shell_config) + wincls, wstate, load_all_shaders, disallow_override_title=bool(args.title), layer_shell_config=run_app.layer_shell_config, x=posX, y=posY) boss = Boss(opts, args, cached_values, global_shortcuts, talk_fd) boss.start(window_id, startup_sessions) if args.debug_font_fallback: diff --git a/kitty/simple_cli_definitions.py b/kitty/simple_cli_definitions.py index 7c3a7c1f9..108c3f5b0 100644 --- a/kitty/simple_cli_definitions.py +++ b/kitty/simple_cli_definitions.py @@ -476,6 +476,11 @@ choices=normal,fullscreen,maximized,minimized,hidden Control how the initial kitty window is created. +--position +type=bool-set +Restores the last session's window position. Does not work on Wayland. + + # Debugging options --version -v