add --modifier alt|super to switch tab chords from Alt to Super
Standalone/DRM and labwc-style hosts (e.g. RPi5) keep Super free, while GNOME steals it, so Alt stays the default. The tab-management prefix modifier (hold=overlay, Up/Down=cycle, Shift+Up/Down=reorder, Delete=close) is now chosen at startup from the xkb keymap (Mod1 or Mod4) with a raw wl_keyboard bit fallback when xkb init fails; Ctrl+Shift+T is unchanged.
This commit is contained in:
parent
f6c1a6b92e
commit
e0af748a4b
3 changed files with 145 additions and 25 deletions
|
|
@ -170,7 +170,9 @@ struct tabbed_server {
|
|||
struct xkb_context *xkb_ctx;
|
||||
struct xkb_keymap *xkb_keymap;
|
||||
struct xkb_state *xkb_state;
|
||||
xkb_mod_index_t xkb_alt_mod;
|
||||
/* Modifier index of the tab-management prefix (Alt or Super/Mod4,
|
||||
per --modifier). */
|
||||
xkb_mod_index_t xkb_prefix_mod;
|
||||
|
||||
/* A client's fullscreen request is honored and mirrored onto the host
|
||||
window, and vice versa. */
|
||||
|
|
@ -279,7 +281,15 @@ static bool shutting_down;
|
|||
so it may carry arguments. */
|
||||
static const char *term_cmd = "alacritty";
|
||||
static bool term_key_held; /* Ctrl+Shift+T currently down (repeat latch) */
|
||||
static bool delete_key_held; /* Alt+Delete currently down (repeat latch) */
|
||||
static bool delete_key_held; /* prefix+Delete currently down (repeat latch) */
|
||||
|
||||
/* The modifier prefix for the tab-management chords: hold = show overlay,
|
||||
Up/Down = cycle, Shift+Up/Down = reorder, Delete = close. Defaults to
|
||||
Alt; --modifier super selects Super (Mod4), which is a good fit for
|
||||
standalone/DRM and labwc-style hosts that do not reserve it the way
|
||||
GNOME does. */
|
||||
enum tabbed_prefix { PREFIX_ALT, PREFIX_SUPER };
|
||||
static enum tabbed_prefix tab_prefix = PREFIX_ALT;
|
||||
|
||||
/* ===================== Clipboard bridge ===================== */
|
||||
|
||||
|
|
@ -3324,8 +3334,12 @@ static void xkb_state_reload(void)
|
|||
if (!server.xkb_keymap)
|
||||
return;
|
||||
server.xkb_state = xkb_state_new(server.xkb_keymap);
|
||||
server.xkb_alt_mod =
|
||||
xkb_keymap_mod_get_index(server.xkb_keymap, XKB_MOD_NAME_ALT);
|
||||
server.xkb_prefix_mod = xkb_keymap_mod_get_index(server.xkb_keymap,
|
||||
tab_prefix == PREFIX_SUPER ? XKB_MOD_NAME_MOD4
|
||||
: XKB_MOD_NAME_ALT);
|
||||
tabbed_log(TABBED_LOG_DEBUG, "tabbed-wlroots: prefix modifier index=%u "
|
||||
"(%s)\n", (unsigned)server.xkb_prefix_mod,
|
||||
tab_prefix == PREFIX_SUPER ? "Super/Mod4" : "Alt");
|
||||
}
|
||||
|
||||
static void host_kbd_keymap(void *data, struct wl_keyboard *kbd, uint32_t format,
|
||||
|
|
@ -3692,6 +3706,18 @@ static struct wl_listener standalone_cursor_motion_listener = {
|
|||
.notify = standalone_cursor_motion,
|
||||
};
|
||||
|
||||
/* Is the configured tab-management prefix (Alt, or Super/Mod4 with
|
||||
--modifier super) currently pressed? Uses the xkb modifier index when a
|
||||
keymap is compiled; with no keymap (xkb init failed) it falls back to the
|
||||
raw wl_keyboard modifier bit: mod1/alt = 1<<3, mod4/super = 1<<6. */
|
||||
static bool prefix_active(uint32_t mods_depressed) {
|
||||
if (server.xkb_state)
|
||||
return xkb_state_mod_index_is_active(server.xkb_state,
|
||||
server.xkb_prefix_mod, XKB_STATE_MODS_EFFECTIVE);
|
||||
return (mods_depressed & (tab_prefix == PREFIX_SUPER ? (1u << 6)
|
||||
: (1u << 3))) != 0;
|
||||
}
|
||||
|
||||
/* Shared key handling for both the host keyboard and native input devices:
|
||||
tab-switch bindings + overlay visibility, with the caller forwarding the
|
||||
key to the seat afterwards. `mods_depressed` uses the wl_keyboard modifier
|
||||
|
|
@ -3710,10 +3736,7 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state,
|
|||
: XKB_KEY_NoSymbol;
|
||||
/* With no compiled keymap (xkb init failed) fall back to the raw
|
||||
evdev keycodes / modifier bits for the hotkey matching below. */
|
||||
bool alt = server.xkb_state
|
||||
? xkb_state_mod_index_is_active(server.xkb_state,
|
||||
server.xkb_alt_mod, XKB_STATE_MODS_EFFECTIVE)
|
||||
: (mods_depressed & (1u << 3)) != 0;
|
||||
bool alt = prefix_active(mods_depressed);
|
||||
if (alt != host.overlay_visible)
|
||||
update_overlay_visible(alt);
|
||||
char symbuf[32];
|
||||
|
|
@ -3787,7 +3810,7 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
/* Alt+Delete closes the active tab. Grabbed so the focused client never
|
||||
/* prefix+Delete closes the active tab. Grabbed so the focused client never
|
||||
sees the key; a latch drops host-synthesized repeats so one hold can't
|
||||
close a tab per repeat. The active surface already moved to the right
|
||||
neighbor inside close_active_tab(), so the tab is gone this frame even
|
||||
|
|
@ -3852,10 +3875,7 @@ static void process_modifiers(uint32_t mods_depressed, uint32_t mods_latched,
|
|||
if (server.xkb_state)
|
||||
xkb_state_update_mask(server.xkb_state, mods_depressed,
|
||||
mods_latched, mods_locked, group, group, group);
|
||||
bool alt = server.xkb_state
|
||||
? xkb_state_mod_index_is_active(server.xkb_state,
|
||||
server.xkb_alt_mod, XKB_STATE_MODS_EFFECTIVE)
|
||||
: (mods_depressed & (1u << 3)) != 0;
|
||||
bool alt = prefix_active(mods_depressed);
|
||||
if (alt != host.overlay_visible)
|
||||
update_overlay_visible(alt);
|
||||
if (host.repeat_key && !alt)
|
||||
|
|
@ -4992,9 +5012,10 @@ int main(int argc, char *argv[]) {
|
|||
/* Ctrl+Shift+T opens a terminal named by $TERMINAL when set, else the
|
||||
alacritty default. Every command-line argument is one tab launcher,
|
||||
except --screen-mode WxH[@Hz], which selects the native output mode and
|
||||
is consumed here. Handle all of this up front so a missing command (or
|
||||
a bad request) can be reported and the process can exit before any
|
||||
window is created. */
|
||||
is consumed here, and --modifier alt|super, which picks the modifier
|
||||
prefix for the tab-management chords. Handle all of this up front so a
|
||||
missing command (or a bad request) can be reported and the process can
|
||||
exit before any window is created. */
|
||||
{
|
||||
const char *env_term = getenv("TERMINAL");
|
||||
if (env_term && env_term[0])
|
||||
|
|
@ -5009,11 +5030,15 @@ int main(int argc, char *argv[]) {
|
|||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
fprintf(stderr,
|
||||
"usage: %s [--screen-mode WxH[@Hz]] [prog...]\n"
|
||||
"usage: %s [--screen-mode WxH[@Hz]] [--modifier alt|super] "
|
||||
"[prog...]\n"
|
||||
" Select the native output mode (standalone only): "
|
||||
"e.g. --screen-mode 1920x1080\n"
|
||||
" or --screen-mode 1920x1080@60. A request nothing "
|
||||
"supports prints every mode and exits.\n"
|
||||
" --modifier picks the tab-management modifier "
|
||||
"(default alt); 'super' suits standalone/DRM and "
|
||||
"labwc-style hosts.\n"
|
||||
" Each <prog> is one shell command; quote it when it "
|
||||
"takes args, e.g. \"firefox -no-remote\".\n"
|
||||
" With no arguments, a single terminal tab opens "
|
||||
|
|
@ -5033,6 +5058,38 @@ int main(int argc, char *argv[]) {
|
|||
val = argv[++i];
|
||||
} else if (strncmp(argv[i], "--screen-mode=", 14) == 0) {
|
||||
val = argv[i] + 14;
|
||||
} else if (strcmp(argv[i], "--modifier") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "tabbed-wlroots: --modifier needs a value, "
|
||||
"e.g. --modifier super\n");
|
||||
free(appv);
|
||||
return 2;
|
||||
}
|
||||
const char *m = argv[++i];
|
||||
if (strcmp(m, "alt") == 0) {
|
||||
tab_prefix = PREFIX_ALT;
|
||||
} else if (strcmp(m, "super") == 0) {
|
||||
tab_prefix = PREFIX_SUPER;
|
||||
} else {
|
||||
fprintf(stderr, "tabbed-wlroots: bad --modifier '%s' "
|
||||
"(use 'alt' or 'super')\n", m);
|
||||
free(appv);
|
||||
return 2;
|
||||
}
|
||||
continue;
|
||||
} else if (strncmp(argv[i], "--modifier=", 11) == 0) {
|
||||
const char *m = argv[i] + 11;
|
||||
if (strcmp(m, "alt") == 0) {
|
||||
tab_prefix = PREFIX_ALT;
|
||||
} else if (strcmp(m, "super") == 0) {
|
||||
tab_prefix = PREFIX_SUPER;
|
||||
} else {
|
||||
fprintf(stderr, "tabbed-wlroots: bad --modifier '%s' "
|
||||
"(use 'alt' or 'super')\n", m);
|
||||
free(appv);
|
||||
return 2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (val) {
|
||||
if (!parse_screen_mode(val)) {
|
||||
|
|
@ -5366,9 +5423,12 @@ int main(int argc, char *argv[]) {
|
|||
launch_client(i);
|
||||
}
|
||||
|
||||
const char *prefix = tab_prefix == PREFIX_SUPER ? "Super" : "Alt";
|
||||
tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: running. "
|
||||
"Alt+Up/Down switches tabs; Alt+Delete closes the active tab; "
|
||||
"Ctrl+Shift+T opens a terminal (%s).\n", term_cmd);
|
||||
"%s+Up/Down switches tabs; %s+Shift+Up/Down reorders; "
|
||||
"%s+Delete closes the active tab; "
|
||||
"Ctrl+Shift+T opens a terminal (%s).\n",
|
||||
prefix, prefix, prefix, term_cmd);
|
||||
|
||||
/* Standalone event loop: no host display, so drive the server loop alone.
|
||||
The native output's frame signal (or the headless 60Hz timer) wakes the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue