178 lines
7.8 KiB
Markdown
178 lines
7.8 KiB
Markdown
# Plan: Keyboard Shortcut to Toggle All Menu Bars (per-window)
|
|
|
|
## Goal
|
|
|
|
Add a configurable keyboard shortcut that shows/hides all the browser's
|
|
"menu bars" — the per-tab toolbars, bookmark bars, and the tab strip —
|
|
**independently per window**. Pressing the shortcut in one window hides
|
|
that window's chrome only; other windows are unaffected. This mirrors how
|
|
the agent sidebar already works (per-window `sidebar_visible` on
|
|
[`window_state_t`](src/tab_manager.c:87)).
|
|
|
|
In sovereign_browser there is no traditional `GtkMenuBar`; each tab's chrome
|
|
is two widgets packed at the top of the tab page
|
|
([`tab->page`](src/tab_manager.c:2966)):
|
|
|
|
1. **`#main-toolbar`** — the horizontal GtkBox holding the hamburger menu
|
|
button, refresh/stop, back, forward, URL entry, and bookmark button
|
|
(built in [`tab_create()`](src/tab_manager.c:2973)).
|
|
2. **`#bookmark-bar`** — the bookmarks toolbar below the URL toolbar
|
|
([`tab->bookmark_bar`](src/tab_manager.c:3089)).
|
|
|
|
Plus the tab strip itself, which is the `GtkNotebook` header, controlled
|
|
via `gtk_notebook_set_show_tabs()`.
|
|
|
|
Hiding all three gives the webview the entire window (a focus / kiosk
|
|
mode). Pressing the shortcut again restores them.
|
|
|
|
## Design
|
|
|
|
### 1. New shortcut action
|
|
|
|
Add `SHORTCUT_TOGGLE_TOOLBARS` to the enum in [`shortcuts.h`](src/shortcuts.h:29)
|
|
(before `SHORTCUT_COUNT`) and a matching entry in the `g_registry` table in
|
|
[`shortcuts.c`](src/shortcuts.c:24):
|
|
|
|
| Field | Value |
|
|
|---------|----------------------------------------------------|
|
|
| id | `toggle_toolbars` |
|
|
| label | `Toggle menu bars` |
|
|
| desc | `Show or hide the tab strip, toolbars, and bookmark bars in the active window` |
|
|
| dflt | `<Control><Shift>m` |
|
|
|
|
Default `<Control><Shift>m` ("m" for menu) is free and mnemonic. It is a
|
|
browser-level shortcut (not consumed by WebKit for web content), so it
|
|
reaches the window-level `on_key_press` handler reliably.
|
|
|
|
Because the settings page enumerates actions via
|
|
[`sovereign://settings/config`](src/nostr_bridge.c:2994) (which loops over
|
|
`SHORTCUT_COUNT` calling [`shortcuts_meta()`](src/shortcuts.c:232) /
|
|
[`shortcuts_get()`](src/shortcuts.c:202)), the new action appears
|
|
automatically in the Keyboard Shortcuts section of
|
|
[`www/settings.html`](www/settings.html:74) with no JS changes. NIP-78 sync
|
|
also picks it up for free via [`shortcuts_serialize()`](src/shortcuts.c:247).
|
|
|
|
### 2. Track toolbar widgets on each tab
|
|
|
|
The `#main-toolbar` GtkBox is currently a local variable in
|
|
[`tab_create()`](src/tab_manager.c:2973) and is not stored on
|
|
[`tab_info_t`](src/tab_manager.h:23). Add a field:
|
|
|
|
```c
|
|
GtkWidget *toolbar; /* #main-toolbar (hamburger + nav + URL) */
|
|
```
|
|
|
|
to `tab_info_t` in [`tab_manager.h`](src/tab_manager.h:23), and assign
|
|
`tab->toolbar = toolbar;` in [`tab_create()`](src/tab_manager.c:2973).
|
|
`tab->bookmark_bar` already exists.
|
|
|
|
### 3. Per-window visibility flag
|
|
|
|
Add a field to [`window_state_t`](src/tab_manager.c:87) in
|
|
[`tab_manager.c`](src/tab_manager.c):
|
|
|
|
```c
|
|
gboolean toolbars_visible; /* per-window menu-bar visibility */
|
|
```
|
|
|
|
Initialize it to `TRUE` for `g_main_window` (in
|
|
[`tab_manager_init`](src/tab_manager.c:3598), near where
|
|
`sidebar_visible = FALSE` is set at line 3643) and for each aux window
|
|
created in [`tab_manager_new_window`](src/tab_manager.c:1262) (near line
|
|
1376 where `sidebar_visible = FALSE` is set).
|
|
|
|
### 4. Toggle function (active window only)
|
|
|
|
Add a public function in [`tab_manager.c`](src/tab_manager.c):
|
|
|
|
```c
|
|
void tab_manager_toggle_toolbars(void);
|
|
```
|
|
|
|
Implementation — mirrors [`tab_manager_toggle_sidebar()`](src/tab_manager.c:4143):
|
|
|
|
1. `window_state_t *ws = get_active_window_state();` — resolves the focused
|
|
window (main or aux), exactly like the sidebar toggle does.
|
|
2. Flip `ws->toolbars_visible`.
|
|
3. `gtk_notebook_set_show_tabs(GTK_NOTEBOOK(ws->notebook), ws->toolbars_visible);`
|
|
— hides/shows the tab strip for this window's notebook only.
|
|
4. Iterate `g_tabs[0..g_tab_count)` and, for each tab whose **page belongs
|
|
to this window's notebook** (use [`tab_find_notebook(tab->page)`](src/tab_manager.c:2660)
|
|
and compare to `ws->notebook`), call
|
|
`gtk_widget_set_visible(tab->toolbar, ws->toolbars_visible)` and
|
|
`gtk_widget_set_visible(tab->bookmark_bar, ws->toolbars_visible)`.
|
|
|
|
This affects only the active window's tabs and tab strip; other windows
|
|
keep their own `toolbars_visible` state.
|
|
|
|
### 5. Respect hidden state for new tabs
|
|
|
|
In [`tab_create()`](src/tab_manager.c:2973), after building `toolbar` and
|
|
`tab->bookmark_bar`, look up the notebook the tab is being added to (the
|
|
target notebook — `g_active_notebook` / `get_effective_notebook()` at tab
|
|
creation time, or `tab_find_notebook(tab->page)` after packing) and its
|
|
`window_state_t` via [`window_state_for_notebook()`](src/tab_manager.c:4051),
|
|
then apply that window's flag:
|
|
|
|
```c
|
|
window_state_t *ws = window_state_for_notebook(<target notebook>);
|
|
gboolean vis = ws ? ws->toolbars_visible : TRUE;
|
|
gtk_widget_set_visible(toolbar, vis);
|
|
gtk_widget_set_visible(tab->bookmark_bar, vis);
|
|
```
|
|
|
|
So a tab opened in a hidden-chrome window is also hidden, while a tab
|
|
opened in a visible-chrome window stays visible. The tab strip visibility
|
|
is per-notebook via `gtk_notebook_set_show_tabs()`, so no extra work is
|
|
needed there.
|
|
|
|
### 6. Dispatch the shortcut
|
|
|
|
Add a case to the switch in [`on_key_press`](src/main.c:611) in
|
|
[`main.c`](src/main.c):
|
|
|
|
```c
|
|
case SHORTCUT_TOGGLE_TOOLBARS:
|
|
tab_manager_toggle_toolbars();
|
|
return TRUE;
|
|
```
|
|
|
|
The key-press handler is window-level, so `get_active_window_state()`
|
|
inside the toggle resolves to the window that had focus when the key was
|
|
pressed — giving the per-window behavior.
|
|
|
|
### 7. Expose in tab_manager.h
|
|
|
|
Add the prototype for `tab_manager_toggle_toolbars(void)` near the other
|
|
toggle prototypes ([`tab_manager_toggle_inspector`](src/tab_manager.h),
|
|
[`tab_manager_toggle_sidebar`](src/tab_manager.h)).
|
|
|
|
## Files touched
|
|
|
|
| File | Change |
|
|
|---------------------|---------------------------------------------------------------|
|
|
| [`src/shortcuts.h`](src/shortcuts.h:29) | Add `SHORTCUT_TOGGLE_TOOLBARS` to enum |
|
|
| [`src/shortcuts.c`](src/shortcuts.c:24) | Add registry entry (id/label/desc/dflt) |
|
|
| [`src/tab_manager.h`](src/tab_manager.h:23) | Add `GtkWidget *toolbar` field + `tab_manager_toggle_toolbars` prototype |
|
|
| [`src/tab_manager.c`](src/tab_manager.c:87) | Add `toolbars_visible` to `window_state_t`; init to TRUE for main + aux windows |
|
|
| [`src/tab_manager.c`](src/tab_manager.c:2973) | Store `tab->toolbar`; apply window's `toolbars_visible` on creation; implement `tab_manager_toggle_toolbars()` (active window only: tab strip + that window's tabs' toolbars/bookmark bars) |
|
|
| [`src/main.c`](src/main.c:611) | Add `case SHORTCUT_TOGGLE_TOOLBARS` dispatch |
|
|
|
|
No changes needed in `www/` (settings page auto-discovers the action) or in
|
|
`settings_sync.c` (NIP-78 sync already serializes all actions).
|
|
|
|
## Verification
|
|
|
|
1. `make` — builds clean.
|
|
2. `./browser.sh restart --login-method generate --url https://example.com`
|
|
3. Press `Ctrl+Shift+M` → in the focused window, toolbars + bookmark bar +
|
|
tab strip disappear; the webview fills the entire window. Press again →
|
|
they reappear.
|
|
4. Open a second window (`Ctrl+N`). Hide chrome in window A with
|
|
`Ctrl+Shift+M`; window B's chrome stays visible. Hide B independently.
|
|
5. With chrome hidden in a window, `Ctrl+T` opens a new tab in that window
|
|
whose toolbars are also hidden; the tab strip stays hidden too.
|
|
6. Open `sovereign://settings` → Keyboard Shortcuts section lists
|
|
"Toggle menu bars" with `Ctrl+Shift+M`; rebind it and confirm the new
|
|
binding works.
|