Skip to content

xquartz: expose the Option layer as a real XKB level - #14

Open
lummi-ch23 wants to merge 1 commit into
XQuartz:masterfrom
lummi-ch23:xquartz-option-level3
Open

lummi-ch23 wants to merge 1 commit into
XQuartz:masterfrom
lummi-ch23:xquartz-option-level3

Conversation

@lummi-ch23

Copy link
Copy Markdown

Problem
On a non-US Mac keyboard layout, Option+key characters (the AltGr / level-3
layer, e.g. @ on Option+G, # on Option+3 on Swiss German) do not reach
XKB-native clients (GTK, Qt) over X11. xev reports the correct keysym, but GTK
apps get the base glyph (g instead of @).

Cause
DarwinBuildModifierMaps rewrites the Option key to XK_Mode_switch when
!XQuartzOptionSendsAlt, and the four glyphs per key are consumed as two
core-protocol groups. Core clients reach the Option layer as group 2 via
Mode_switch, but XKB-native clients resolve levels/groups through the XKB state,
where Mode_switch is a level shifter and the key types built from the width-4
core map are two-level. Level 3 is therefore unreachable and the app falls back to
the base glyph. The existing code even comments "Yes, this is ugly."

Fix
Map the Option key to XK_ISO_Level3_Shift on Mod5 and, after
XkbApplyMappingChange, install a genuine FOUR_LEVEL key type for each key that
carries an Option-layer glyph, laying the four glyphs out as one group of four
levels (base, shift, option, option+shift). XKB-native clients then reach the
Option layer as level 3, matching how a native Linux ch(de_mac) layout presents
it. Core-protocol behaviour is unchanged.

Testing
Built on Apple Silicon against the 2.8.6 SDK (-Dxquartz=true -Dsecure-rpc=false -Dxcsecurity=true), installed over X11.bin. Verified with a real keypress:
Option+G yields @ and Option+3 yields # in GTK apps (Intune portal,
xfce4-terminal); confirmed via xev and xkbcomp -xkb that the G key now has a
four-level type with @ at level 3 and Option on Mod5. ssh -X untrusted
forwarding works (SECURITY extension enabled).

On a non-US Mac keyboard layout, Option+key characters (the AltGr / level-3 layer,
e.g. @ on Option+G, # on Option+3 on Swiss German) do not reach XKB-native clients
(GTK, Qt) over X11. xev reports the correct keysym, but GTK apps get the base glyph.

DarwinBuildModifierMaps rewrites the Option key to XK_Mode_switch when
!XQuartzOptionSendsAlt, and the four glyphs per key are consumed as two
core-protocol groups. Core clients reach the Option layer as group 2 via
Mode_switch, but XKB-native clients resolve levels through the XKB state, where the
key types built from the width-4 core map are two-level; level 3 is unreachable and
the app falls back to the base glyph.

Map the Option key to XK_ISO_Level3_Shift on Mod5 and, after XkbApplyMappingChange,
install a FOUR_LEVEL key type and switch each Option-bearing key to one group of it
via XkbChangeTypesOfKey, which resizes the symbol map and keeps width/offset/
group_info consistent. XKB-native clients then reach the Option layer as level 3.

The new type slot is memset and its level_names/preserve populated before use:
XkbAllocClientMap does not clear a slot that fits existing slack, and an
uninitialised level_names pointer crashed XkbCopyKeymap (memmove) during
device-class copy on the next key event. Assigning types with XkbChangeTypesOfKey
rather than hand-editing width/offset is what keeps the keymap copy-safe.

Tested on Apple Silicon (2.8.6 SDK, -Dxcsecurity=true): Option+G yields @ and
Option+3 yields # in GTK apps, verified via xev and xkbcomp; ssh -X works.

Signed-off-by: Christoph Lumme <christoph.lumme@siemens.com>
@lummi-ch23
lummi-ch23 force-pushed the xquartz-option-level3 branch from f208803 to 68f6c1c Compare September 11, 2026 23:37
@lummi-ch23

Copy link
Copy Markdown
Author

Updated the branch: the first revision crashed the server (SIGSEGV in XkbCopyKeymap/_XkbCopyClientMap memmove during device-class copy on the next key event). Root cause: the new FOUR_LEVEL type slot was not zeroed before XkbResizeKeyType (XkbAllocClientMap does not clear a slot that fits existing size_types slack), leaving level_names a garbage pointer, and the key symbol map was hand-edited (width/offset) inconsistently. Fixed by zeroing + populating the type slot and assigning it via XkbChangeTypesOfKey, which resizes the symbol map and keeps width/offset/group_info consistent. Verified with a real keypress on Apple Silicon (2.8.6 SDK).

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