Files
sovereign_browser/plans/toggle-menu-bars.md
T

7.8 KiB

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).

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):

  1. #main-toolbar — the horizontal GtkBox holding the hamburger menu button, refresh/stop, back, forward, URL entry, and bookmark button (built in tab_create()).
  2. #bookmark-bar — the bookmarks toolbar below the URL toolbar (tab->bookmark_bar).

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 (before SHORTCUT_COUNT) and a matching entry in the g_registry table in shortcuts.c:

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 (which loops over SHORTCUT_COUNT calling shortcuts_meta() / shortcuts_get()), the new action appears automatically in the Keyboard Shortcuts section of www/settings.html with no JS changes. NIP-78 sync also picks it up for free via shortcuts_serialize().

2. Track toolbar widgets on each tab

The #main-toolbar GtkBox is currently a local variable in tab_create() and is not stored on tab_info_t. Add a field:

GtkWidget     *toolbar;       /* #main-toolbar (hamburger + nav + URL) */

to tab_info_t in tab_manager.h, and assign tab->toolbar = toolbar; in tab_create(). tab->bookmark_bar already exists.

3. Per-window visibility flag

Add a field to window_state_t in tab_manager.c:

gboolean       toolbars_visible;   /* per-window menu-bar visibility */

Initialize it to TRUE for g_main_window (in tab_manager_init, near where sidebar_visible = FALSE is set at line 3643) and for each aux window created in tab_manager_new_window (near line 1376 where sidebar_visible = FALSE is set).

4. Toggle function (active window only)

Add a public function in tab_manager.c:

void tab_manager_toggle_toolbars(void);

Implementation — mirrors tab_manager_toggle_sidebar():

  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) 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(), 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(), then apply that window's flag:

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 in main.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, tab_manager_toggle_sidebar).

Files touched

File Change
src/shortcuts.h Add SHORTCUT_TOGGLE_TOOLBARS to enum
src/shortcuts.c Add registry entry (id/label/desc/dflt)
src/tab_manager.h Add GtkWidget *toolbar field + tab_manager_toggle_toolbars prototype
src/tab_manager.c Add toolbars_visible to window_state_t; init to TRUE for main + aux windows
src/tab_manager.c 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 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.