Skip to content

Develop - #50

Merged
KonstantinMerkel merged 106 commits into
masterfrom
develop
Oct 31, 2026
Merged

KonstantinMerkel merged 106 commits into
masterfrom
develop

Conversation

@KonstantinMerkel

Copy link
Copy Markdown
Owner

Next big version upgrade.

Test phase started...

KonstantinMerkel and others added 30 commits June 19, 2026 17:29
Moved architecture.md, layouts.md, vision.md to docs/
Added Issues and Feature Requests to CONTRIBUTING.md
Restructured CONTRIBUTING.md topics to follow the typical development process
Added a Summary, Customization Information to README.md and restructured the file

---------

Co-authored-by: Alexander Pechmann <alexander.pechmann@hm.edu>
Co-authored-by: Konstantin Merkel <konstantin.merkel@tutanota.de>
#8)

* refactor(keybindings): transition to native Mutter intercept and SRP architecture

* chore: update docs acccordingly

* feat: implement dynamic schema shadowing for custom keybindings

* docs: add dynamic schema shadowing architecture documentation
…rst fully working version

- Added cross-monitor dragging with dynamic visual N+1 and N-1 matrix previews
- Introduced 'Monitor Transition Behavior' settings ('Escalate' vs 'Swap')
- Implemented floating fallback when attempting to drag over a monitor at maximum layout capacity
- Resolved cross-monitor preview bugs by cleanly reverting both source and target tracker geometries
- Prevented drag-and-drop desync bugs during rapid movements by calculating monitor indices using absolute pointer geometry instead of global.display.get_current_monitor()
- Updated keybinding logic and restored missing dragging indicator styles
- Extensive unit tests covering cross-monitor transitions and regressions
Apps may maximize or fullscreen their tiled windows themselves depending
on a setting: never, only listed apps (popular browsers by default) or
all except listed apps (LibreOffice and OrcaSlicer by default). Other
apps are put back into their tile, as before.

A focus policy decides what happens to a maximized window when another
window of its layout gains focus or opens: keep it, unmaximize it, or
pass the maximization on. Except under keep, a layout holds one
maximized window at a time.

Dropping a dragged window on the top screen edge maximizes it in its
tile, Super+Down only ends a maximization, and the maximize button can
be hidden from all title bars through button-layout, with the original
layout saved before it is changed.

The override rules live in lib/domain/policies/override/ (toggle,
self-maximize, focus); preferences get a Maximizing page.
A client constrains only the size of a tile. When the answer to a
request arrives at another position, as when an unmaximize races the
request in Mutter, the frame is requested once more; a repeat that lands
elsewhere again is left alone.
A window that cannot be resized reported its current size as its size
limits, which is 0x0 before it has a frame; clampToLimits then shrank
the tile request to an empty frame. Limits of zero or less now count
as unknown, and fixed-size windows report limits only once they have
a frame.
A new hotplug-policy setting (Monitors page) chooses between
restore-by-monitor, the previous behaviour, and follow-primary: the
primary monitor's windows move to whichever monitor becomes primary,
and that monitor's own windows are evacuated until it is secondary
again. A primary changed in the display settings counts as a hotplug.
prefs.js only composes the window now. General, Keyboard Shortcuts,
Maximizing, Monitors and the layout pages each live in prefs/, and the
shared choice row moves to prefs/rows.js.
zip -r added to an existing extension.zip, so files deleted from the
tree (the whole pre-rewrite lib/) stayed in the package. pack now
removes the old archive first and leaves gschemas.compiled out: GNOME
44+ compiles the schema on install, and the review guidelines ask for
the XML only.
master holds the pre-rewrite architecture; every patch on it is already
in develop (git cherry finds none missing). develop's tree is kept as is,
so the release PR into master merges without conflicts.
Nothing is translated, and the review guidelines ask for no
unnecessary keys in metadata.json.
The General and Keyboard Shortcuts pages never disconnected their
settings listeners. The preferences process outlives its window, so a
later settings change ran the handlers on disposed widgets. The
Maximizing page's disconnect-on-destroy pattern moves to
pageListener() in prefs/rows.js and is used by all three pages.
Missing or misspelled estate fields became NaN and passed every bounds check,
which made the Reconciler re-issue frames on every flush. Zero-size estates
and non-integer count keys ("1.5") were accepted as well.
extensions.gnome.org only allows letters, digits, spaces and dots.
after-used skipped unused parameters in front of a used one, so a forgotten
argument there went unnoticed. Placeholders that GTK / Mutter callbacks need
for their positional signature are now prefixed with an underscore.
Any single key could be recorded as a global shortcut, so pressing q bound plain
q and blocked typing it. Shortcuts now need a modifier other than Shift (Shift
and AltGr only pick the typed character) and must pass Gtk.accelerator_valid,
which also rejects lone lock keys, AltGr and Tab. Escape now closes the dialog
instead of being recorded.
Lowering a fixed workspace count emits only notify::n-workspaces, not
workspace-removed, so dead workspace tokens were never pruned. A redock then
restored the evacuated window onto the removed MetaWorkspace, whose freed
window list Mutter reads in change_workspace(). With the token pruned it was
an endless setFrame loop instead.

Workspaces are now also synced on notify::n-workspaces and when resuming from
suspension. Evacuated windows of a removed workspace lose their evacuated state:
Mutter already moved them to another workspace, and they stay minimized there
like any other minimized window.
A tile smaller than the gaps clamped to 0, and set_size(0, …) lets a
Wayland client pick its own size.
Mutter ends the drag of a closing window from an unmanaged handler connected at
drag begin, so it runs after ShellEvents has already unregistered the window.
The grab-op-end then names an unknown window and never reaches the Engine, and
engine.grab stayed set: the focus policy ignored every focus change until the
next drag or resize. The same happened when tiling was suspended mid-drag.

The Engine now clears the grab when its window goes away and on suspend.
Restored windows were placed in the order they had opened. Each one takes its
remembered slot among the windows already back, so a layout rearranged before
undocking came back mixed up: [C, B, A] returned as [C, A, B]. The restores are
now sorted by remembered slot, floating windows last.
GNOME marks an extension whose enable() throws as failed and never calls
disable(), so everything set up until then stayed: settings handlers, the
hidden maximize button, keybinding takeovers. enable() now calls disable() on a
throw and rethrows. Each part is assigned only once built, and disable() skips
the parts that were never built; an error during that cleanup is logged and the
original error still reaches GNOME.
A monitor change sets topologyChanging and clears it after the next flush.
An exception before that callback was registered left the flag set, and every
later window move was ignored until the next login. The flag is now cleared
from a finally.
…contexts

The prefs widgets are only freed when the prefs process exits, so the page
destroy handlers and vfunc_dispose overrides never ran in time; at exit GJS
blocked every JS vfunc_dispose with a Gjs-CRITICAL (52 per closed window).
WindowConnections, created per window in prefs.js, now holds every settings
connection and drops them on close-request; the destroy handlers and dispose
overrides are gone.

Both draw funcs end with cr.$dispose(): GJS frees a context only on GC, which
does not see Cairo's memory (~9 KB kept per redraw).
…aller files

prefs/preview.js (532 lines) keeps the page; drawing and hit-testing move to
prefs/layout-canvas.js, the split dialog to prefs/split-dialog.js.

tests/prefs.test.js (966 lines) becomes one file per page in tests/prefs/,
with the GI and settings fakes shared from tests/helpers/prefs-fakes.js. The
35 tests are unchanged.
@KonstantinMerkel
KonstantinMerkel merged commit b78af1c into master Oct 31, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants