wl9 is a POSIX wayland server that presents its windows to Plan 9's rio.
It communicates over 9p to an exportfs instance running host Plan
9 system through a pair of file descriptors (one for reading, and
one for writing).
A lightly patched version of sigrid's c9 library is used as a 9p client.
wl9 [-t rfd[,wfd]] [cmd [args...]]
The -t option specifies the file descriptors for the 9p connection.
They should be set up in advance before running wl9, or if not
specified, /dev/virtio-ports/term is opened for reading and
writing.
If cmd [args...] is given, it is launched as a child process after
wl9 sets up its sockets. The first window created by the child
will run in the existing /mnt/wsys instead of mounting $wsys.
This has the effect of replacing the window running exportfs.
Additionally, wl9 will stop automatically when it has no clients.
You can connect through a virtio-serial pipe from a unix guest to a host 9front system.
vmx -c virtio:name:term!^<>{exportfs -r / -m 32768 >[1=0]}
If the guest system has hotplug rules to create named symlinks for
virtio pipes, you can just run wl9. Otherwise, you will need to
setup the appropriate redirections.
wl9 -t 0 <>/dev/vportNpM
You can use a pipeline with exportfs and ssh to remotely run a
wayland application on a unix server that has wl9 installed.
exportf -r / <[0=1] | ssh host wl9 -t 0,1 cmd >[1=0]
rio windows can be created in two ways: by writing a new message
to /dev/wctl, or by attaching to $wsys with a new message as
the aname. Unfortunately, with the first method we can't find the
winid of the created window, so wl9 uses the second method.
However, attaching to $wsys poses an additional problem: we either
need a separate 9p channel for exportfs -S $wsys, or we need to
speak 9p over 9p to a separate exportfs process spawned by the
original.
At least for now, wl9 uses a third approach. Using a small exportfs patch, we can attach to services by walking to their fid, and attaching with a 12 character aname prefix consisting of an 11 character decimal fid number, and a blank. The prefix is stripped for the mount of the service.
Once we mount $wsys, wl9 opens several files:
winname: used to locate the draw(3) image for the windowlabel:xdg_toplevel.set_titlerequests are translated to writes tolabelwctl: used to monitor window coordinates and statusmouse: used to read mouse eventskbd: used to read keyboard events
Still kind of buggy with some applications.
Not implemented yet.
For key codes, we use the 'k' and 'K' events from /dev/kbd. These
codes are the unshifted unicode characters corresponding to the
keys pressed and released. If there is no unshifted character
corresponding to that scancode, or the scancode is escaped, the
shifted character is used instead.
In typical keymaps, some keys are mapped to same unshifted character, i.e. the mapping from scancode to character is not 1-1. Unfortunately, This means that we can't distinguish which of the keys were pressed. If there is a conflict, we choose the first one we encounter.
In particular, for the default kbmap, we have
| rune | key (scan) ... |
|---|---|
| \n | ENTER (1c) KPENTER (e0 1c) |
| - | MINUS (0c) KPMINUS (4a) |
| . | DOT (34) KPDOT (53) |
| / | SLASH (35) KPSLASH (e0 35) |
| 0 | 0 (0b) KP0 (52) |
| 1 | 1 (02) KP1 (4f) |
| 2 | 2 (03) KP2 (50) |
| 3 | 3 (04) KP3 (51) |
| 4 | 4 (05) KP4 (4b) |
| 5 | 5 (06) KP5 (4c) |
| 6 | 6 (07) KP6 (4d) |
| 7 | 7 (08) KP7 (47) |
| 8 | 8 (09) KP8 (48) |
| 9 | 9 (0a) KP9 (49) |
| Kup | UP (e0 48) ? (7b) ? (e0 79) |
| Kshift | LEFTSHIFT (2a) RIGHTSHIFT (36) |
| Kctl | LEFTCTRL (1d) RIGHTCTRL (e0 1d) CAPSLOCK (3a) |
| Kdown | DOWN (e0 50) ? (79) |
At startup, /dev/kbmap is translated to an XKB keymap as follows:
For every keymap entry with table 0 (unshifted) 2 (escaped unshifted),
5 (escaped with control), or 6 (escaped with shift), we add a keycode
<U+XXXX> to the xkb_keycodes section with value 0xXXXX + 8,
where U+XXXX is the value of mapped unicode character. The 8
offset is due to historical reasons to translate an kernel event
code to an XKB keycode.
We use the standard 2-level xkb_types (excluding KEYPAD since
we can't uniquely identify those keys). Currently, tables 3-9 in
/dev/kbmap are ignored, which means that shift only affects
non-escaped keycodes, and control, alt, and mod4.
xkb_types "plan9" {
type "ONE_LEVEL" {
modifiers = none;
level_name[1] = "Any";
};
type "TWO_LEVEL" {
modifiers = Shift;
map[Shift] = 2;
level_name[1] = "Base";
level_name[2] = "Shift";
};
type "ALPHABETIC" {
modifiers = Shift+Lock;
map[Shift] = 2;
map[Lock] = 2;
level_name[1] = "Base";
level_name[2] = "Caps";
};
};
We use the following xkb_compat rules for standard shift/caps
lock handling.
xkb_compat "plan9" {
interpret Shift_L {
action = SetMods(modifiers=Shift,clearLocks);
};
interpret Caps_Lock {
action = LockMods(modifiers=Lock);
};
};
The xkb_symbols section is constructed with a key for each keycode.
Since XKB keysyms are more granular than Plan 9 key characters, for
the ambiguous cases, we choose keysyms corresponding to first key
in the table above. Additionally, though Plan 9 doesn't have a
keymap entry the right meta key (bug?), Kmod4 is mapped to Super_L
rather than Super_R.
If that keycode corresponds to an non-escaped scancode and that
scancode has an entry in table 1 (shift) as well, we add a two-level
key, key <U+XXXX> {[KEY0, KEY1]}, where KEY0 and KEY1 are the
names of the XKB symbols we mapped the table 0 and table 1 characters
to. Otherwise, we add a one-level key fkey <U+XXXX> {[KEY02]}.
If there is no XKB name for the character, we use an XKB unicode
keysym.