Metadata-Version: 2.4
Name: centre
Version: 0.10.1
Summary: Your Window Position Manager
Author-email: Jack Scott <cloner.bl12@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/JackScott7/centre
Project-URL: Repository, https://github.com/JackScott7/centre
Project-URL: Issues, https://github.com/JackScott7/centre/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Operating System :: Microsoft :: Windows
Classifier: Environment :: Win32 (MS Windows)
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: keyboard>=0.13.5
Requires-Dist: psutil>=7.2.2
Requires-Dist: pydantic>=2.13.4
Requires-Dist: pygetwindow>=0.0.9
Requires-Dist: pywin32>=312
Requires-Dist: watchdog>=6.0.0
Dynamic: license-file

# Centre

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PyPI version](https://badge.fury.io/py/centre.svg)](https://badge.fury.io/py/centre)
[![Python Versions](https://img.shields.io/pypi/pyversions/centre.svg)](https://pypi.org/project/centre/)
---

Centre is your window position manager.

Take control of your windows by choosing where they appear, how they’re arranged, and what size they should be.

Consistency is `centre`'s goal.


## Preview
https://github.com/user-attachments/assets/d088a951-8c6b-4731-8228-80b063f1a6e5

## What Centre Tries to Achieve

Centre was built for users who want consistent window placement across desktop sessions.

## Requirements

- Windows
- Python 3.10 or newer

# Install

```PowerShell
pip install centre
```

# Update

```PowerShell
pip install -U centre
```

## Start Centre Automatically

To do that, create a Windows Task Scheduler task.

Run the following command as Administrator in PowerShell/cmd to create a Task in Windows Task Scheduler.
```PowerShell
schtasks /Create /TN "centre" /SC ONLOGON /TR "centre -s" /RL LIMITED /F
```

# Usage

After your window configuration is ready, start the listener:

```PowerShell
centre -s
```

## Single-Instance Listener

Centre allows one `centre --start` listener per Windows login session. If a
listener is already running, another start attempt prints
`Centre already running` and exits.

The other CLI commands remain available while the listener is running.

## Stopping Centre

When Centre is running interactively in a terminal, press `Ctrl+C` to stop it.
Centre will remove its keyboard hooks and stop its configuration observer
before exiting.

# The CLI

The action flags are mutually exclusive, so use one action per invocation.

| Command                      | Description                                                 |
|------------------------------|-------------------------------------------------------------|
| `centre -s`, `--start`       | Start the listener.                                         |
| `centre -l`, `--list`        | Print window titles, sizes, and positions as formatted JSON. |
| `centre -c`, `--read-config` | Print the loaded and validated configuration.               |
| `centre -v`, `--version`     | Print the installed Centre version.                         |
| `centre -h`, `--help`        | Show the available CLI options.                             |

## Automatic Configuration Reload

While Centre is running, it watches `config.json` for changes. Saving a valid
change reloads presets, ignored applications, logging settings, and action-sound
preferences without restarting the process.

Keyboard shortcuts are registered when the listener starts. Changing a shortcut
in `bindings` or `wm.presets` requires you to stop and restart Centre before the
new shortcut is used. Setting `wm.enabled` to `false` stops registered Focus
Window actions immediately; enabling it or adding a Focus Window shortcut
requires a restart so the keyboard hook can be registered.

If `config.json` is invalid at startup, Centre reports the problem and exits
without starting the listener. If a saved configuration becomes invalid while
Centre is running, Centre performs an orderly shutdown. Correct `config.json`,
then run `centre --start` again.

# Window Configuration (config.json)

Your config will be created at the first startup in:

CMD

```cmd
%USERPROFILE%\.centre\config.json
```

PowerShell

```PowerShell
$env:USERPROFILE\.centre\config.json
```

The default config includes these values:

- The resolution key is based on your display resolution.

```json
{
    "logging": false,
    "play_sound": {
        "center": false,
        "capture": false,
        "ignore": false
    },
    "predefined_keybindings": {
        "enabled": true,
        "bindings": {
            "center": "ctrl+alt+d",
            "minimize": "ctrl+alt+m",
            "capture": "ctrl+alt+p",
            "ignore_preset": "ctrl+alt+i",
            "center_all": "ctrl+alt+a"
        }
    },
    "wm": {
        "enabled": false,
        "target_preset": "",
        "presets": []
    },
    "presets": {
        "1920x1080": {}
    },
    "ignored_presets": []
}
```

## Configuration Validation and Migration

Centre validates the complete configuration, including window presets,
predefined keyboard shortcuts, Focus Window hotkey syntax, and action-sound
preferences. Unknown configuration fields, shortcut names, and preset
properties are rejected.

When a valid configuration is missing fields that have defaults, Centre adds
those defaults and writes the migrated configuration back to `config.json`.

The listener requires `predefined_keybindings.enabled` to be `true`. If it is
`false`, `centre --start` exits instead of continuing without keyboard
shortcuts.

## Logging

File logging is disabled by default. To enable it, set `logging` to `true` in
`config.json`:

```json
{
  "logging": true
}
```

When logging is enabled, Centre creates or appends to:

```text
%USERPROFILE%\.centre\centre.log
```

While Centre is running, saving a valid configuration change applies the new
logging setting without requiring a restart. Changing `logging` to `false`
closes the file handler and stops new log entries from being written.

Log entries include a timestamp, severity level, and message:

```text
[2026-07-27 12:34:56,789] INFO - Centering NOTEPAD
```

Centre logs window-management activity and errors. Entries may contain
normalized executable names and captured preset details. The log file is
append-only and is not automatically rotated or deleted.

## Action Sounds

Action sounds are disabled by default. Enable only the confirmations you want
under `play_sound` in `config.json`:

```json
{
    "play_sound": {
        "center": true,
        "capture": true,
        "ignore": true
    }
}
```

The `center` setting applies to both the active-window Center action and Center
All. The `capture` and `ignore` settings control their corresponding actions.
Centre plays a sound only after an action succeeds; pressing Ignore for an
application that is already ignored does not play another confirmation.

Saving valid action-sound changes applies them immediately while the listener
is running. No restart is required.

## Focus Window Shortcuts

Focus Window assigns a shortcut directly to an application WindowPreset. It is
disabled by default and does not launch applications that are not already open.

The configured `executable` must exactly match a key in the selected target
layout. Captured WindowPreset keys are uppercase and omit `.exe`, such as
`WINDOWSTERMINAL`.

```json
{
    "wm": {
        "enabled": true,
        "target_preset": "1920x1080",
        "presets": [
            {
                "center_on_focus": true,
                "executable": "WINDOWSTERMINAL",
                "hotkey": "ctrl+alt+1",
                "title_contains": "PowerShell"
            }
        ]
    }
}
```

- `enabled` controls the complete Focus Window feature and defaults to `false`.
- `target_preset` selects the layout containing the required WindowPresets. If
  exactly one layout exists and this value is empty, Centre selects and saves it
  automatically. With multiple layouts, configure the target explicitly.
- `executable` must exactly match a WindowPreset key under `target_preset`.
- `hotkey` is validated when the configuration loads.
- `title_contains` optionally narrows matches using a case-insensitive title
  substring. Use `null` when the executable match is sufficient.
- `center_on_focus` defaults to `false`. When `true`, Centre focuses the window
  and then applies its position and size from the target layout.

If multiple visible windows match, Centre keeps the active match when possible;
otherwise it focuses the first match returned by Windows. Minimized matches are
restored before activation.

Focus Window shortcuts must be unique. If any two Focus Window shortcuts are
equivalent, or one conflicts with a predefined Centre shortcut, none of the
Focus Window shortcuts are registered. Invalid hotkey names make the
configuration invalid.

Changing a Focus Window hotkey, executable, or title filter requires a listener
restart. Layout positions and `target_preset` are read from the current valid
configuration when a registered shortcut runs. Disabling `wm` or removing its
WindowPreset prevents a previously registered callback from acting.

___

Window presets should be placed inside the "presets" object in `config.json`.

## Capture a Window

Focus the window you want to capture and press `ctrl+alt+p`. Centre stores its
current position and size under the current display resolution.

Captured windows are identified by their executable name without the `.exe`
extension. The name is normalized to uppercase, for example:

- `notepad++.exe` becomes `NOTEPAD++`
- `WindowsTerminal.exe` becomes `WINDOWSTERMINAL`

Executable names remain stable when an application changes its window title,
such as when switching tabs in Notepad++.

Capturing the same application again updates its existing preset.

## Ignore a Window Preset

Focus the window you want Centre to ignore and press `ctrl+alt+i`. Centre adds
the active application's executable name to `ignored_presets`.

Ignored applications are skipped when you press the center shortcut. Centre will
not apply the application's custom preset or `Default_Position`.

To allow Centre to manage the application again, remove its executable name from
`ignored_presets` in `config.json`.

## Center All Configured Windows

Press `ctrl+alt+a` to apply presets to all currently open windows that have a
matching entry under the current display resolution.

Centre skips open windows that do not have a named preset or whose executable
appears in `ignored_presets`. `Default_Position` is only used by the regular
center shortcut for the active window.
___

A window preset should look like this:

```json
{
    "NOTEPAD++": {
        "LEFT": 224,
        "TOP": 168,
        "SIZE_X": 1473,
        "SIZE_Y": 697
    },
    "Default_Position": {
        "LEFT": 25,
        "TOP": 34,
        "SIZE_X": 1860,
        "SIZE_Y": 980
    }
}

```

- Be sure to add `Default_Position` in your presets under the generated default resolution.
  When Centre does not find the active window in your presets, it uses `Default_Position` as the fallback size and position.

- `Default_Position` is useful when you have a list of apps that you have set a custom position for,
  but intend to keep all other apps in one specific location.

## Default Shortcuts

| Action     | Shortcut     | Description                                                  |
|------------|--------------|--------------------------------------------------------------|
| Center     | `ctrl+alt+d` | Apply the active application's preset or `Default_Position`. |
| Minimize   | `ctrl+alt+m` | Minimize the active window.                                  |
| Capture    | `ctrl+alt+p` | Save or update the active application's position and size.   |
| Ignore     | `ctrl+alt+i` | Add the active application to `ignored_presets`.             |
| Center All | `ctrl+alt+a` | Apply presets to all matching open windows.                  |

Focus Window shortcuts have no defaults; define them individually under
`wm.presets`.

Your final config should look something like this:

```json
{
    "logging": true,
    "play_sound": {
        "center": true,
        "capture": true,
        "ignore": true
    },
    "predefined_keybindings": {
        "enabled": true,
        "bindings": {
            "center": "ctrl+alt+d",
            "minimize": "ctrl+alt+m",
            "capture": "ctrl+alt+p",
            "ignore_preset": "ctrl+alt+i",
            "center_all": "ctrl+alt+a"
        }
    },
    "wm": {
        "enabled": true,
        "target_preset": "1920x1080",
        "presets": [
            {
                "center_on_focus": true,
                "executable": "WINDOWSTERMINAL",
                "hotkey": "ctrl+alt+1",
                "title_contains": null
            }
        ]
    },
    "presets": {
        "1920x1080": {
          "WINDOWSTERMINAL": {
                "LEFT": 217,
                "TOP": 169,
                "SIZE_X": 1486,
                "SIZE_Y": 695
            },
            "NOTEPAD++": {
                "LEFT": -5,
                "TOP": 374,
                "SIZE_X": 1930,
                "SIZE_Y": 664
            },
            "Default_Position": {
                "LEFT": 25,
                "TOP": 34,
                "SIZE_X": 1860,
                "SIZE_Y": 980
            }
        }
    },
    "ignored_presets": [
        "EXPLORER"
    ]
}
```

# Changelog

See [CHANGELOG.md](CHANGELOG.md) for release history.


# License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
