diff --git a/kitty/boss.py b/kitty/boss.py index 991ca92b4..2421cd084 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -471,6 +471,8 @@ class Boss: opts_for_size: Options | None = None, startup_id: str | None = None, override_title: str | None = None, + x: int | None = None, + y: int | None = None, ) -> int: if os_window_id is None: size_data = get_os_window_sizing_data(opts_for_size or get_options(), startup_session) @@ -483,7 +485,7 @@ class Boss: os_window_id = create_os_window( initial_window_size_func(size_data, self.cached_values), pre_show_callback, - wtitle or appname, wname, wclass, wstate, disallow_override_title=bool(wtitle)) + wtitle or appname, wname, wclass, wstate, disallow_override_title=bool(wtitle), x=x, y=y) else: wname = self.args.name or self.args.cls or appname wclass = self.args.cls or appname @@ -954,6 +956,9 @@ class Boss: args.session = '' if not os.path.isabs(args.directory): args.directory = os.path.join(data['cwd'], args.directory) + pos_x, pos_y = None, None + if args.position and not is_wayland(): + pos_x, pos_y = map(int, args.position.lower().partition('x')[::2]) from .child import process_env clean_env = process_env(data['environ']) focused_os_window = os_window_id = 0 @@ -970,7 +975,7 @@ class Boss: wstate = args.start_as if args.start_as and args.start_as != 'normal' else None os_window_id = self.add_os_window( session, wclass=args.cls, wname=args.name, opts_for_size=opts, startup_id=startup_id, - override_title=args.title or None, window_state=wstate) + override_title=args.title or None, window_state=wstate, x=pos_x, y=pos_y) if session.focus_os_window: focused_os_window = os_window_id if opts.background_opacity != get_options().background_opacity: diff --git a/kitty/launch.py b/kitty/launch.py index f64823b4a..5ade54e10 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -13,6 +13,7 @@ from .child import Child from .cli import parse_args from .cli_stub import LaunchCLIOptions from .clipboard import set_clipboard_string, set_primary_selection +from .constants import is_wayland from .fast_data_types import add_timer, get_boss, get_options, get_os_window_title, patch_color_profiles from .options.utils import env as parse_env from .tabs import Tab, TabManager @@ -358,6 +359,12 @@ choices=normal,fullscreen,maximized,minimized The initial state for the newly created OS Window. +--os-window-position +The position, for example :code:`10x20`, on screen at which to place the newly +created OS Window. This may or may not work depending on the policies of the +desktop environment/window manager. It never works on Wayland. + + --logo completion=type:file ext:png group:"PNG images" relative:conf Path to a PNG image to use as the logo for the newly created window. See @@ -455,6 +462,13 @@ def layer_shell_config_from_panel_opts(panel_opts: Iterable[str]) -> LayerShellC return layer_shell_config(opts) +def parse_os_window_position(position: str) -> tuple[int | None, int | None]: + if not position or is_wayland(): + return None, None + x, _, y = position.lower().partition('x') + return int(x), int(y) + + def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Tab | None, next_to: Window | None, add_to_session: str) -> Tab: def create_tab(tm: TabManager | None = None) -> Tab: @@ -462,11 +476,13 @@ def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Tab | None, n if opts.type == 'os-panel': oswid = boss.add_os_panel(layer_shell_config_from_panel_opts(opts.os_panel), opts.os_window_class, opts.os_window_name) else: + x, y = parse_os_window_position(opts.os_window_position) oswid = boss.add_os_window( wclass=opts.os_window_class, wname=opts.os_window_name, window_state=opts.os_window_state, - override_title=opts.os_window_title or None) + override_title=opts.os_window_title or None, + x=x, y=y) tm = boss.os_window_map[oswid] tab = tm.new_tab(empty_tab=True, location=opts.location) if opts.tab_title: @@ -871,7 +887,7 @@ def clone_safe_opts() -> frozenset[str]: return frozenset(( 'window_title', 'tab_title', 'type', 'keep_focus', 'cwd', 'var', 'hold', 'location', 'os_window_class', 'os_window_name', 'os_window_title', 'os_window_state', - 'logo', 'logo_position', 'logo_alpha', 'spacing', 'next_to', 'hold_after_ssh' + 'os_window_position', 'logo', 'logo_position', 'logo_alpha', 'spacing', 'next_to', 'hold_after_ssh' )) diff --git a/kitty/rc/launch.py b/kitty/rc/launch.py index b0aa50479..1ea995b75 100644 --- a/kitty/rc/launch.py +++ b/kitty/rc/launch.py @@ -54,6 +54,7 @@ class Launch(RemoteCommand): os_window_name/str: WM_NAME for OS Window os_window_class/str: WM_CLASS for OS Window os_window_state/choices.normal.fullscreen.maximized.minimized: The initial state for OS Window + os_window_position/str: The position for OS Window color/list.str: list of color specifications such as foreground=red watcher/list.str: list of paths to watcher files bias/float: The bias with which to create the new window in the current layout diff --git a/kitty/simple_cli_definitions.py b/kitty/simple_cli_definitions.py index 3bfddedd8..bcb82b59e 100644 --- a/kitty/simple_cli_definitions.py +++ b/kitty/simple_cli_definitions.py @@ -490,7 +490,8 @@ specified in the session file gets overriden. --position -The position, for example 10x20, on screen at which to place the first kitty OS Window. +The position, for example 10x20, on screen at which to place the first kitty OS Window +created by this invocation. This may or may not work depending on the policies of the desktop environment/window manager. It never works on Wayland. See also :opt:`remember_window_position` to have kitty automatically try