diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5bd5137 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# build output, published as a release attachment +*.shell-extension.zip diff --git a/hangul-overview-latin@timothykim.net/extension.js b/hangul-overview-latin@timothykim.net/extension.js new file mode 100644 index 0000000..1e13b50 --- /dev/null +++ b/hangul-overview-latin@timothykim.net/extension.js @@ -0,0 +1,56 @@ +import IBus from 'gi://IBus'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js'; +import { + getInputSourceManager, + INPUT_SOURCE_TYPE_XKB, + INPUT_SOURCE_TYPE_IBUS, +} from 'resource:///org/gnome/shell/ui/status/keyboard.js'; +import {getIBusManager} from 'resource:///org/gnome/shell/misc/ibusManager.js'; + +export default class HangulOverviewLatin extends Extension { + enable() { + this._showingId = Main.overview.connect('showing', + () => this._ensureLatin()); + } + + disable() { + Main.overview.disconnect(this._showingId); + this._showingId = null; + } + + _ensureLatin() { + const ism = getInputSourceManager(); + const src = ism.currentSource; + if (src?.type !== INPUT_SOURCE_TYPE_IBUS || !src.id.startsWith('hangul')) + return; + + // ibus-hangul's InputMode handler toggles regardless of the state + // argument, so only activate it when currently in Hangul mode. + const prop = this._findProp(src.properties, 'InputMode'); + if (prop) { + if (prop.get_state() === IBus.PropState.CHECKED) { + getIBusManager().activateProperty( + prop.get_key(), IBus.PropState.UNCHECKED); + } + return; + } + + // No InputMode property: switch to the first xkb source instead + for (const i of Object.keys(ism.inputSources)) { + if (ism.inputSources[i].type === INPUT_SOURCE_TYPE_XKB) { + ism.inputSources[i].activate(true); + return; + } + } + } + + _findProp(props, key) { + for (let i = 0, prop; (prop = props?.get(i)); i++) { + if (prop.get_key() === key) + return prop; + } + return null; + } +} diff --git a/hangul-overview-latin@timothykim.net/metadata.json b/hangul-overview-latin@timothykim.net/metadata.json new file mode 100644 index 0000000..b9f134d --- /dev/null +++ b/hangul-overview-latin@timothykim.net/metadata.json @@ -0,0 +1,7 @@ +{ + "uuid": "hangul-overview-latin@timothykim.net", + "name": "Hangul Overview Latin", + "description": "Switch ibus-hangul to Latin input when the Activities Overview opens, so search works immediately.", + "shell-version": ["50"], + "url": "" +} diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..56a2572 --- /dev/null +++ b/plan.md @@ -0,0 +1,102 @@ +# hangul-overview-latin — GNOME Shell Extension Plan + +## Goal +When the Activities Overview opens, ensure input is in Latin mode so overview search works immediately, even if ibus-hangul was in Hangul mode. + +## Environment +- Fedora Workstation, vanilla GNOME, Wayland +- ibus-hangul input engine (`hangul` IBus engine) +- GNOME 45+ extension format (ESM `import`, `metadata.json` with appropriate `shell-version`) + - **First step: check actual Shell version** with `gnome-shell --version` and set `shell-version` accordingly. + +## Approach + +Two candidate strategies, in order of preference: + +### Strategy A (primary): switch input source to English on overview open +- Use `getInputSourceManager()` from `resource:///org/gnome/shell/ui/status/keyboard.js`. +- On `Main.overview` `showing` signal, if current source is `hangul`, activate the `xkb:us::eng` (or first non-IBus) source. +- Pros: simple, engine-agnostic, reliable. +- Cons: changes the *source*, not the internal hangul/latin mode. User must switch source back (Super+Space) after leaving overview. +- Optional enhancement: remember previous source and restore it on `hidden` signal. **Decide during implementation** — restoring may be annoying if the user starts typing an app name and launches it (focus lands in new app with Hangul source restored). Ship without restore first; add behind a pref if wanted. + +### Strategy B (stretch): flip ibus-hangul's internal InputMode to latin +- ibus-hangul ≥ 1.5.15 exposes an `InputMode` property via the IBus property API. +- From a Shell extension, reach it through `IBus.Bus` → global engine property activation: `ibus.set_global_engine()` is not needed; instead use `IBusManager` (`misc/ibusManager.js`) and `activateProperty('InputMode.Latin', ...)` style calls — **verify exact property key** by running `ibus engine hangul` and inspecting with `ibus` introspection or reading ibus-hangul source (`src/engine.c`, property name is likely `InputMode`). +- Pros: user stays on hangul source; just the mode flips — closest to the stated desire. +- Cons: depends on ibus-hangul version/property names; more fragile. + +Plan: implement A first, get it working, then attempt B as a follow-up. If B works, prefer it and drop the source-switching path. + +## File Structure +``` +hangul-overview-latin@timothykim.net/ +├── metadata.json +└── extension.js +``` +No prefs UI in v1. If restore-on-hide becomes a toggle, add `prefs.js` + GSettings schema later. + +## metadata.json +```json +{ + "uuid": "hangul-overview-latin@timothykim.net", + "name": "Hangul Overview Latin", + "description": "Switch to Latin input when the Activities Overview opens", + "shell-version": ["48"], + "url": "" +} +``` +(Adjust `shell-version` to actual.) + +## extension.js sketch (Strategy A) +```js +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import {getInputSourceManager} from 'resource:///org/gnome/shell/ui/status/keyboard.js'; + +export default class HangulOverviewLatin { + enable() { + this._ism = getInputSourceManager(); + this._showingId = Main.overview.connect('showing', () => { + const current = this._ism.currentSource; + if (current?.type === 'ibus' && current.id.startsWith('hangul')) { + const sources = this._ism.inputSources; + for (const i in sources) { + if (sources[i].type === 'xkb') { sources[i].activate(); break; } + } + } + }); + } + disable() { + Main.overview.disconnect(this._showingId); + this._showingId = null; + this._ism = null; + } +} +``` +**Verify against actual keyboard.js API for the installed Shell version** — property names (`currentSource`, `inputSources`, `activate()`) drift between releases. Read `/usr/share/gnome-shell/` resources or upstream source for the matching tag. + +## Implementation Steps +1. `gnome-shell --version`; note version. +2. Scaffold extension dir under `~/.local/share/gnome-shell/extensions/`. +3. Confirm the extension class shape against GNOME 45+ docs (`Extension` base class from `resource:///org/gnome/shell/extensions/extension.js` is the current convention — use it, not a bare class). +4. Implement Strategy A. +5. Test (see below). +6. Investigate Strategy B: inspect ibus-hangul property names, try `Main.panel.statusArea` / `IBusManager` property activation from Looking Glass (`lg`) interactively before writing code. +7. If B works, gate A behind it or remove. + +## Testing (Wayland) +- No `Alt+F2 r` restart on Wayland. Options: + - Nested session: `dbus-run-session -- gnome-shell --nested --wayland` (extension must be enabled inside it), or + - Log out/in per iteration. +- Use Looking Glass (`lg` via run dialog... unavailable on Wayland restart-free flow; still usable for live inspection: Super, type `lg` won't work — use `Alt+F2` is X11-only; on Wayland open Looking Glass via `global.context` from a nested session or use `journalctl -f -o cat /usr/bin/gnome-shell` for logs). +- Log with `console.log()`; watch `journalctl --user -f | grep -i hangul`. +- Test matrix: + - Hangul source + hangul mode → Super → search types Latin. + - Already on English source → Super → no-op. + - Rapid open/close of overview → no signal leaks (check `disable()`/re-enable cycles). + +## Edge Cases / Open Questions +- Overview also opens via hot corner and `Super` in app grid state — `showing` signal covers all entry paths; confirm. +- `disable()` must disconnect signals (EGO review requirement if ever published). +- Interaction with Super+Space source cycling while overview is open. +- Does typing in overview search re-trigger IBus engine focus? (Search entry is a Clutter/St entry; IBus applies — that's why the problem exists at all.)