diff --git a/README.md b/README.md index f3513c8..7f055e0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# tabbed-wlroots +# kick A nested Wayland compositor (built on wlroots) that presents several client apps as tabs in a single window on the host Wayland compositor. @@ -17,7 +17,7 @@ meson setup build meson compile -C build ``` -The resulting binary is `build/tabbed-wlroots`. +The resulting binary is `build/kick`. The Wayland protocol stubs (`xdg-shell`, `xdg-decoration`, `wlr-data-control-unstable-v1`) are not committed; they are generated into @@ -71,33 +71,33 @@ install works too. ## Usage ``` -tabbed-wlroots [--start-cmd-index N] [prog...] +kick [--start-cmd-index N] [prog...] ``` Each `` is one shell command; quote it when it takes arguments, e.g. -`tabbed-wlroots "foot -e htop" "firefox -no-remote"`. With no arguments, a +`kick "foot -e htop" "firefox -no-remote"`. With no arguments, a single terminal tab is opened (see `$TERMINAL` below). `--start-cmd-index N` starts focused on command `N` (1-based; the last command by default). -`tabbed-wlroots -h` prints this usage. +`kick -h` prints this usage. Every argument starts a new tab. There is no tab-count limit. Client apps run -as children of tabbed-wlroots and connect to its private Wayland socket, so -`DISPLAY` is unset for them and their `WAYLAND_DISPLAY` points at the tabbed +as children of kick and connect to its private Wayland socket, so +`DISPLAY` is unset for them and their `WAYLAND_DISPLAY` points at the kick compositor (clients are launched with the GDK and Qt Wayland backends forced). `Alt+Shift+T` opens the terminal named by the `$TERMINAL` environment variable when it is set (see Key bindings); otherwise it falls back to `alacritty`. The value is used verbatim, so it may carry arguments, e.g. -`TERMINAL="foot -e htop" tabbed-wlroots ...`. +`TERMINAL="foot -e htop" kick ...`. Notes: - An argument written bare (starting with `-`) is taken as a tab launcher too (unless quoted); a warning is printed when it looks like a stray option. - Each command (an argument or the default `$TERMINAL`) is resolved on `PATH` - before the session starts: if its program isn't found, tabbed-wlroots prints + before the session starts: if its program isn't found, kick prints an error and exits non-zero without opening any window. - The client applications run inside the session, so closing their windows - only closes their tab; closing the host tabbed-wlroots window, or sending + only closes their tab; closing the host kick window, or sending SIGINT/SIGTERM, shuts the whole session down and kills all client children. ### Startup order @@ -122,7 +122,7 @@ the default last one. If a command never connects — e.g. `sleep 999` — the rest of the command line still starts (they all launched together) and the window shows the last tab as soon as it is ready. A command whose whole process group exits -without ever connecting (e.g. `tabbed-wlroots /bin/false`) drops its tab +without ever connecting (e.g. `kick /bin/false`) drops its tab entirely instead of leaving a permanent black hole. Closing a tab takes it out of the list for good: its slot is removed and @@ -156,16 +156,16 @@ new-tab chord follows the prefix like every other binding. The `Super` variant is meant for standalone/DRM and labwc-style hosts (including the Raspberry Pi, where nothing reserves it); under GNOME the host grabs most `Super` chords before the nested compositor ever sees them -(e.g. `Super+Up` maximizes the tabbed window), so keep the default `Alt` +(e.g. `Super+Up` maximizes the kick window), so keep the default `Alt` there. labwc's own defaults also leave `Super+Shift+arrow` and -`Super+Delete` free even when tabbed is nested inside labwc. +`Super+Delete` free even when kick is nested inside labwc. Holding the tab-management modifier (`Alt`, or `Super` with `--modifier super`) shows a passive overlay listing every tab's title with the active tab highlighted; the list updates live as you cycle with `Up`/`Down` -and disappears on release. It is drawn by tabbed itself, so it works +and disappears on release. It is drawn by kick itself, so it works on hosts with or without a title bar (the overlay text uses a system font -via FreeType; set `TABBED_FONT` to pick one). Each row also shows the +via FreeType; set `KICK_FONT` to pick one). Each row also shows the tab's app icon, resolved from its Wayland `app_id` via the desktop files and icon themes in `XDG_DATA_DIRS` (PNG via libpng, SVG via librsvg); tabs without a resolvable icon get a generic placeholder. @@ -188,7 +188,7 @@ moving it (same synthesized repeat as cycling). An `Alt+Shift+T` inside the moved tab opens exactly where the reordered list says it should — immediately right of the tab's new position. -Both `Alt+Up/Down` and `Alt+Shift+Up/Down` are grabbed: tabbed consumes them +Both `Alt+Up/Down` and `Alt+Shift+Up/Down` are grabbed: kick consumes them so the focused client never receives the chord (e.g. a terminal can't act on `Shift`+arrow while you reorder). @@ -206,36 +206,36 @@ browser's `F11`). Fullscreen mirrors between the host window and the clients: -- Fullscreen the tabbed window (use your host compositor's fullscreen +- Fullscreen the kick window (use your host compositor's fullscreen keybinding, or an app's own `F11`) and every tab is told it is fullscreen, so clients drop their decorations and fill the screen. - A client that requests fullscreen itself (e.g. a video player) also - fullscreens the tabbed host window. + fullscreens the kick host window. - Leaving fullscreen returns every tab to maximized. -## Standalone mode (`TABBED_MODE=standalone`) +## Standalone mode (`KICK_MODE=standalone`) -By default tabbed-wlroots runs **nested**: it opens a window on the host +By default kick runs **nested**: it opens a window on the host Wayland compositor and draws every tab inside that single window. Set -`TABBED_MODE=standalone` to instead become its own Wayland compositor, +`KICK_MODE=standalone` to instead become its own Wayland compositor, rendering directly onto a native display (DRM via wlroots) — the first output -only; extra monitors are ignored. In this mode tabbed-wlroots takes over the +only; extra monitors are ignored. In this mode kick takes over the screen, and the tab overlay is composited onto the output in a second render pass instead of being drawn into a host window. -- `TABBED_MODE=standalone WLR_BACKENDS=...` selects the wlroots backends +- `KICK_MODE=standalone WLR_BACKENDS=...` selects the wlroots backends (wlroots' own `WLR_BACKENDS` variable is passed through). With no `WLR_BACKENDS` it defaults to `drm,libinput`. - `WAYLAND_DISPLAY` is ignored in standalone mode (it never connects to an outer compositor), except as part of the requested `WLR_BACKENDS`. -- Real keyboard/pointer devices are attached to the tabbed seat directly +- Real keyboard/pointer devices are attached to the kick seat directly (native input); the `Alt+Shift+T` and `Alt`-overlay hotkeys still work off those devices. - `Ctrl-Alt-F1..F12` switch virtual terminals while running on the DRM backend (via libseat/logind); the terminal sees nothing of the chord. - The stdin event feed used by the test harness works identically in both modes, so the same synthesized-input tests cover nested and standalone runs. -- Headless testing: `TABBED_MODE=standalone WLR_BACKENDS=headless` runs +- Headless testing: `KICK_MODE=standalone WLR_BACKENDS=headless` runs standalone on wlroots' headless backend (no DRM needed), useful in CI or when no TTY is available. @@ -244,7 +244,7 @@ pass instead of being drawn into a host window. `./test.sh` runs the nested suite against the desktop, so each test briefly opens the compositor's host window. `./test-headless.sh` re-hosts those windows inside an invisible compositor: it boots a second, standalone -instance of the same binary (`TABBED_MODE=standalone WLR_BACKENDS=headless`, +instance of the same binary (`KICK_MODE=standalone WLR_BACKENDS=headless`, output shown nowhere) and points `WAYLAND_DISPLAY` at it for the pytest run, so nothing flashes on the desktop. No extra dependencies. @@ -254,10 +254,10 @@ that the desktop session uses. Standalone mode needs that data-control `set_selection` request handled too, which is the case regardless of which runner you use. -## Logging (`TABBED_LOG`) +## Logging (`KICK_LOG`) Quiet by default: a plain launch prints nothing to the launching terminal -except fatal errors. Set `TABBED_LOG` before starting: +except fatal errors. Set `KICK_LOG` before starting: | Value | Meaning | |-------|------------------------------------------------------------------| @@ -268,22 +268,22 @@ except fatal errors. Set `TABBED_LOG` before starting: At debug level (`2`) client programs also inherit the launching terminal's stdout/stderr instead of being silenced, which makes client errors visible. -## Frame dumps (SIGUSR1 / TABBED_AUTODUMP) +## Frame dumps (SIGUSR1 / KICK_AUTODUMP) -The `SIGUSR1` signal and `TABBED_AUTODUMP` write raw `P6` portable-pixmap +The `SIGUSR1` signal and `KICK_AUTODUMP` write raw `P6` portable-pixmap files to `/tmp` regardless of the log level: - `SIGUSR1` writes `/tmp/scene_N.ppm` — the composed scene (whatever - tabbed-wlroots rendered for the host). + kick rendered for the host). - `SIGUSR1` writes `/tmp/host_N.ppm` — the host compositor's back buffer, so you can see what the host actually displayed. In standalone mode this is the composited frame being presented to the output (scene plus the `Alt` overlay). - `N` is an incrementing per-run counter; a single `SIGUSR1` produces a matching scene/host pair. -- With `TABBED_AUTODUMP` (any value, e.g. `TABBED_AUTODUMP=1`), a scene and +- With `KICK_AUTODUMP` (any value, e.g. `KICK_AUTODUMP=1`), a scene and host dump are taken automatically once the first frame in which a client committed a CPU-readable (shared-memory) buffer — handy for capturing exactly what a newly launched client drew. -- At `TABBED_LOG=2` the diagnostic that detects the client's own shm buffer +- At `KICK_LOG=2` the diagnostic that detects the client's own shm buffer additionally writes that buffer to `/tmp/client_N.ppm`. \ No newline at end of file diff --git a/build.sh b/build.sh index 3ce30e4..3868f6f 100755 --- a/build.sh +++ b/build.sh @@ -8,4 +8,4 @@ cd "$(dirname "$0")" set -x meson setup build --reconfigure meson compile -C build -echo "Built: ./build/tabbed-wlroots" +echo "Built: ./build/kick" diff --git a/tabbed-wlroots.c b/kick.c similarity index 93% rename from tabbed-wlroots.c rename to kick.c index acbd8e4..959121b 100644 --- a/tabbed-wlroots.c +++ b/kick.c @@ -1,4 +1,4 @@ -/* tabbed-wlroots.c -- nested tabbed compositor built on wlroots 0.19. +/* kick.c -- nested kick compositor built on wlroots 0.19. * * Renders a headless wlroots output (via wlr_scene) inside a host Wayland * window (the "host" connection, e.g. labwc). Input from the host is @@ -96,7 +96,7 @@ /* ===================== Server-side (wlroots) state ===================== */ -struct tabbed_app { +struct kick_app { char *cmd; pid_t pid; /* Process group the *connected* client lives in. Command-line commands @@ -150,7 +150,7 @@ struct tabbed_app { enum { ORIGIN_CLI, ORIGIN_ADD_TAB, ORIGIN_SUB, ORIGIN_EXTERNAL } origin; /* For ORIGIN_SUB: the tab owning the connected client this window belongs to (the "parent" tab its slot is glued right of). */ - struct tabbed_app *parent_app; + struct kick_app *parent_app; /* The user closed this tab (Alt+Delete). While set, cycle_tab skips the slot and the SIGKILL escalation timer (close_timer) may still be armed; @@ -159,7 +159,7 @@ struct tabbed_app { struct wl_event_source *close_timer; }; -struct tabbed_server { +struct kick_server { struct wl_display *wl_display; struct wl_event_loop *loop; struct wlr_backend *backend; @@ -194,8 +194,8 @@ struct tabbed_server { the overlay title -- from the very first frame and the user only waits for it. A slot that is active while still pending (no toplevel yet) shows the black backdrop and clear seat focus until it maps. */ - struct tabbed_app *active_app; - struct tabbed_app **apps; + struct kick_app *active_app; + struct kick_app **apps; int num_apps; int apps_cap; @@ -212,7 +212,7 @@ struct tabbed_server { /* Standalone (real output) mode: the output is driven directly by a native backend (DRM/headless) instead of being blitted into a host - window. Set from TABBED_MODE=standalone or a forced WLR_BACKENDS. */ + window. Set from KICK_MODE=standalone or a forced WLR_BACKENDS. */ bool standalone; bool standalone_headless; struct wlr_session *session; @@ -247,7 +247,7 @@ struct overlay_glyph { int top; /* y offset of the glyph top from the row top */ }; -struct tabbed_host { +struct kick_host { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; @@ -304,9 +304,9 @@ struct tabbed_host { enum { REPEAT_CYCLE, REPEAT_REORDER } repeat_kind; }; -static struct tabbed_server server; -static struct tabbed_host host; -static char tabbed_socket[64]; +static struct kick_server server; +static struct kick_host host; +static char kick_socket[64]; static char socket_path[256]; static volatile sig_atomic_t needs_redraw; static bool frame_pending; @@ -325,8 +325,8 @@ static bool delete_key_held; /* prefix+Delete currently down (repeat latch) */ 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; +enum kick_prefix { PREFIX_ALT, PREFIX_SUPER }; +static enum kick_prefix tab_prefix = PREFIX_ALT; /* ===================== Clipboard bridge ===================== */ @@ -399,7 +399,7 @@ static void bridge_cleanup(void); static void bridge_init(void); static void bridge_attach_seat(void); -/* Frame dumps: SIGUSR1 (or TABBED_AUTODUMP) requests a scene-buffer save +/* Frame dumps: SIGUSR1 (or KICK_AUTODUMP) requests a scene-buffer save (client content as wlroots drew it) and a host back-buffer save (what we composited for the host) on the next frame. */ static volatile sig_atomic_t dump_scene_req, dump_host_req; @@ -417,84 +417,84 @@ static volatile sig_atomic_t sigchld_seen = 0; Alt+Shift+T terminal. Slots are otherwise removed outright, so a live check is all that's needed to know whether a slot should be shown, cycled to, or handed the active crown. */ -static bool app_live(struct tabbed_app *app); +static bool app_live(struct kick_app *app); /* The currently focused toplevel (NULL while the active slot is black). */ static struct wlr_xdg_toplevel *active_toplevel(void); -static void set_active_app(struct tabbed_app *app); +static void set_active_app(struct kick_app *app); static void set_active_surface(struct wlr_xdg_toplevel *toplevel); static void render_and_present(void); -static struct tabbed_app *app_for_toplevel(struct wlr_xdg_toplevel *toplevel); -static int app_index(struct tabbed_app *app); -static struct tabbed_app *pick_successor(struct tabbed_app *app, +static struct kick_app *app_for_toplevel(struct wlr_xdg_toplevel *toplevel); +static int app_index(struct kick_app *app); +static struct kick_app *pick_successor(struct kick_app *app, int prefer_right); static void remove_app(int idx); static int add_tab(const char *cmd); static int cmd_in_path(const char *cmd); -static void insert_app_after(struct tabbed_app *app, struct tabbed_app *anchor); -static void launch_client(struct tabbed_app *app); +static void insert_app_after(struct kick_app *app, struct kick_app *anchor); +static void launch_client(struct kick_app *app); static void launch_all_cli(void); /* Logging levels: quiet by default so a plain launch writes nothing to the - launching terminal except fatal errors. TABBED_LOG=1 shows status lines, - TABBED_LOG=2 adds the per-frame [diag] trace. SIGUSR1 and TABBED_AUTODUMP + launching terminal except fatal errors. KICK_LOG=1 shows status lines, + KICK_LOG=2 adds the per-frame [diag] trace. SIGUSR1 and KICK_AUTODUMP dumps always write their .ppm files regardless of level. */ -enum { TABBED_LOG_QUIET = 0, TABBED_LOG_INFO = 1, TABBED_LOG_DEBUG = 2 }; +enum { KICK_LOG_QUIET = 0, KICK_LOG_INFO = 1, KICK_LOG_DEBUG = 2 }; -static int tabbed_log_level(void) { +static int kick_log_level(void) { static volatile sig_atomic_t level = -1; if (level < 0) { - const char *v = getenv("TABBED_LOG"); + const char *v = getenv("KICK_LOG"); int l = v ? atoi(v) : 0; - if (l < TABBED_LOG_QUIET) l = TABBED_LOG_QUIET; - if (l > TABBED_LOG_DEBUG) l = TABBED_LOG_DEBUG; + if (l < KICK_LOG_QUIET) l = KICK_LOG_QUIET; + if (l > KICK_LOG_DEBUG) l = KICK_LOG_DEBUG; level = l; } return level; } -static void tabbed_vlog(int level, const char *fmt, va_list args) { - if (level > tabbed_log_level()) +static void kick_vlog(int level, const char *fmt, va_list args) { + if (level > kick_log_level()) return; vfprintf(stderr, fmt, args); } -static void tabbed_log(int level, const char *fmt, ...) { +static void kick_log(int level, const char *fmt, ...) { va_list args; va_start(args, fmt); - tabbed_vlog(level, fmt, args); + kick_vlog(level, fmt, args); va_end(args); } /* Route libxkbcommon's own log output (which otherwise writes - "xkbcommon: ERROR: ..." straight to stderr, bypassing TABBED_LOG) through + "xkbcommon: ERROR: ..." straight to stderr, bypassing KICK_LOG) through our level system. Errors surface at info level; warnings and below are debug-only, so a quiet launch no longer leaks parse failures to the launching terminal. */ -static void tabbed_xkb_log(struct xkb_context *ctx, enum xkb_log_level level, +static void kick_xkb_log(struct xkb_context *ctx, enum xkb_log_level level, const char *fmt, va_list args) { (void)ctx; - int l = (level <= XKB_LOG_LEVEL_ERROR) ? TABBED_LOG_INFO : TABBED_LOG_DEBUG; - if (l > tabbed_log_level()) + int l = (level <= XKB_LOG_LEVEL_ERROR) ? KICK_LOG_INFO : KICK_LOG_DEBUG; + if (l > kick_log_level()) return; - fputs("tabbed-wlroots: xkbcommon: ", stderr); + fputs("kick: xkbcommon: ", stderr); vfprintf(stderr, fmt, args); } -static void tabbed_log_level_init(void) { - (void)tabbed_log_level(); +static void kick_log_level_init(void) { + (void)kick_log_level(); } /* The process group to signal for an app: the group its claimed client lives in (set at claim time), falling back to the launcher pid for slots with no client yet. */ -static pid_t app_signal_group(struct tabbed_app *app) { +static pid_t app_signal_group(struct kick_app *app) { return (app && app->pgid > 0) ? app->pgid : (app ? app->pid : -1); } /* Whether an app has a killable target: either a process group we own, or a connected client pid (external clients sharing our own group). */ -static bool app_killable(struct tabbed_app *app) { +static bool app_killable(struct kick_app *app) { return app && (app_signal_group(app) > 0 || app->client_pid > 0); } @@ -504,7 +504,7 @@ static bool app_killable(struct tabbed_app *app) { (e.g. started from the same terminal as the compositor), is signaled by pid alone: group-signaling it would kill the launcher's session, ourselves included. */ -static void kill_app(struct tabbed_app *app, int sig) { +static void kill_app(struct kick_app *app, int sig) { pid_t g = app_signal_group(app); if (g > 0 && g != getpgid(0)) kill(-g, sig); @@ -570,7 +570,7 @@ struct standalone_ptrdev { allocation failure. The buffer is freed in shutdown_cleanup(). */ static int apps_ensure_cap(int n) { if (n <= server.apps_cap) return 0; - struct tabbed_app **grown = + struct kick_app **grown = realloc(server.apps, (size_t)n * sizeof(*grown)); if (!grown) return -1; server.apps = grown; @@ -578,7 +578,7 @@ static int apps_ensure_cap(int n) { return 0; } -static bool app_live(struct tabbed_app *app) { +static bool app_live(struct kick_app *app) { return app && (app->toplevel || app->pending_claim); } @@ -655,7 +655,7 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC pfn_glEGLImageTargetTexture2DOES; static void *egl_proc(const char *name) { void *p = (void *)eglGetProcAddress(name); if (!p) - fprintf(stderr, "tabbed-wlroots: EGL proc %s unavailable\n", name); + fprintf(stderr, "kick: EGL proc %s unavailable\n", name); return p; } @@ -668,7 +668,7 @@ static GLuint compile_shader(GLenum type, const char *src) { if (!ok) { char log[512]; glGetShaderInfoLog(sh, sizeof(log), NULL, log); - fprintf(stderr, "tabbed-wlroots: shader error: %s\n", log); + fprintf(stderr, "kick: shader error: %s\n", log); glDeleteShader(sh); return 0; } @@ -708,7 +708,7 @@ static bool gl_setup(void) { if (!ok) { char log[512]; glGetProgramInfoLog(host.gl_program, sizeof(log), NULL, log); - fprintf(stderr, "tabbed-wlroots: link error: %s\n", log); + fprintf(stderr, "kick: link error: %s\n", log); return false; } host.gl_pos_loc = glGetAttribLocation(host.gl_program, "a_pos"); @@ -830,7 +830,7 @@ static const char *overlay_pick_font(void) { "/usr/share/fonts/liberation/LiberationSans-Regular.ttf", "/usr/share/fonts/noto/NotoSans-Regular.ttf", }; - const char *env = getenv("TABBED_FONT"); + const char *env = getenv("KICK_FONT"); if (env && access(env, R_OK) == 0) return env; for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) @@ -852,24 +852,24 @@ static void overlay_font_init(void) { if (!overlay_ft_lib) { const char *path = overlay_pick_font(); if (!path) { - tabbed_log(TABBED_LOG_INFO, "[overlay] no font found; " - "set TABBED_FONT to enable overlay text\n"); + kick_log(KICK_LOG_INFO, "[overlay] no font found; " + "set KICK_FONT to enable overlay text\n"); return; } overlay_font_path = path; if (FT_Init_FreeType(&overlay_ft_lib) != 0) { - tabbed_log(TABBED_LOG_INFO, "[overlay] FreeType init failed\n"); + kick_log(KICK_LOG_INFO, "[overlay] FreeType init failed\n"); return; } if (FT_New_Face(overlay_ft_lib, path, 0, &overlay_ft_face) != 0) { - tabbed_log(TABBED_LOG_INFO, "[overlay] cannot load font %s\n", path); + kick_log(KICK_LOG_INFO, "[overlay] cannot load font %s\n", path); FT_Done_FreeType(overlay_ft_lib); overlay_ft_lib = NULL; return; } } if (FT_Set_Pixel_Sizes(overlay_ft_face, 0, px) != 0) { - tabbed_log(TABBED_LOG_INFO, "[overlay] cannot set pixel size %d\n", px); + kick_log(KICK_LOG_INFO, "[overlay] cannot set pixel size %d\n", px); return; } @@ -892,7 +892,7 @@ static void overlay_font_init(void) { unsigned char *atlas = calloc((size_t)atlas_w * atlas_h * 2, 1); if (!atlas) { - tabbed_log(TABBED_LOG_INFO, "[overlay] atlas alloc failed\n"); + kick_log(KICK_LOG_INFO, "[overlay] atlas alloc failed\n"); return; } int n_glyphs = 0; @@ -953,7 +953,7 @@ static void overlay_font_init(void) { free(atlas); host.overlay_font_h = height; overlay_font_ok = server.overlay_atlas_wlr != NULL; - tabbed_log(TABBED_LOG_INFO, "[overlay] font %s glyphs=%d atlas=%dx%d\n", + kick_log(KICK_LOG_INFO, "[overlay] font %s glyphs=%d atlas=%dx%d\n", overlay_font_path, n_glyphs, atlas_w, atlas_h); return; } @@ -973,7 +973,7 @@ static void overlay_font_init(void) { host.overlay_atlas_h = atlas_h; host.overlay_font_h = height; overlay_font_ok = true; - tabbed_log(TABBED_LOG_INFO, "[overlay] font %s glyphs=%d atlas=%dx%d\n", + kick_log(KICK_LOG_INFO, "[overlay] font %s glyphs=%d atlas=%dx%d\n", overlay_font_path, n_glyphs, atlas_w, atlas_h); } @@ -1258,7 +1258,7 @@ static unsigned char *overlay_load_svg(const char *path, int *w, int *h) { /* Resolve and upload `app`'s icon as a GL_RGBA texture (host EGL context must be current). Best-effort: on any failure the app keeps no icon and the overlay draws the placeholder instead. */ -static void overlay_icon_load(struct tabbed_app *app) { +static void overlay_icon_load(struct kick_app *app) { app->icon_resolved = true; const char *app_id = app->toplevel ? app->toplevel->app_id : NULL; if (!app_id || !app_id[0]) @@ -1310,7 +1310,7 @@ static void overlay_icon_load(struct tabbed_app *app) { app->icon_w = w; app->icon_h = h; if (app->icon_wlr) - tabbed_log(TABBED_LOG_INFO, "[overlay] icon %s %dx%d\n", app_id, w, h); + kick_log(KICK_LOG_INFO, "[overlay] icon %s %dx%d\n", app_id, w, h); return; } @@ -1329,7 +1329,7 @@ static void overlay_icon_load(struct tabbed_app *app) { app->icon_tex = tex; app->icon_w = w; app->icon_h = h; - tabbed_log(TABBED_LOG_INFO, "[overlay] icon %s %dx%d\n", app_id, w, h); + kick_log(KICK_LOG_INFO, "[overlay] icon %s %dx%d\n", app_id, w, h); } static void draw_rect(int x, int y, int w, int h, @@ -1411,7 +1411,7 @@ static void fit_text(const char *src, int max_px, char *out, int out_sz) } if (max_px < dot_w) return; - tabbed_log(TABBED_LOG_DEBUG, "[overlay] ellipsis: '%s' budget=%d\n", + kick_log(KICK_LOG_DEBUG, "[overlay] ellipsis: '%s' budget=%d\n", src, max_px); int w = 0; size_t n = 0; @@ -1437,7 +1437,7 @@ static void fit_text(const char *src, int max_px, char *out, int out_sz) /* Row title for an overlay slot: the mapped toplevel's title, or the command line for a still-black (pending) tab. */ -static const char *app_row_title(struct tabbed_app *app) { +static const char *app_row_title(struct kick_app *app) { if (app->toplevel && app->toplevel->title && app->toplevel->title[0]) return app->toplevel->title; if (app && app->cmd && app->cmd[0]) @@ -1447,7 +1447,7 @@ static const char *app_row_title(struct tabbed_app *app) { /* A row in the overlay (both the host-GL and the standalone wlr paths): skip slots that are dead or mid-close; black pending tabs are rows too. */ -static bool app_overlay_row(struct tabbed_app *app) { +static bool app_overlay_row(struct kick_app *app) { return app_live(app) && !app->closing; } @@ -1460,7 +1460,7 @@ static void draw_tab_overlay(void) { if (row_h < icon_sz + 4) row_h = icon_sz + 4; int max_row_w = 0, n_rows = 0; for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *app = server.apps[i]; + struct kick_app *app = server.apps[i]; if (!app_overlay_row(app)) continue; if (!app->icon_resolved) overlay_icon_load(app); @@ -1493,7 +1493,7 @@ static void draw_tab_overlay(void) { int row = 0; for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *app = server.apps[i]; + struct kick_app *app = server.apps[i]; if (!app_overlay_row(app)) continue; const char *title = app_row_title(app); char fallback[16]; @@ -1590,7 +1590,7 @@ static void overlay_pass_text(struct wlr_render_pass *pass, const char *s, } static void overlay_pass_icon(struct wlr_render_pass *pass, - struct tabbed_app *app, + struct kick_app *app, int ix, int iy, int size, float alpha) { if (!app || !app->icon_wlr) return; @@ -1613,7 +1613,7 @@ static void draw_tab_overlay_pass(struct wlr_render_pass *pass) { if (row_h < icon_sz + 4) row_h = icon_sz + 4; int max_row_w = 0, n_rows = 0; for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *app = server.apps[i]; + struct kick_app *app = server.apps[i]; if (!app_overlay_row(app)) continue; if (!app->icon_resolved) overlay_icon_load(app); @@ -1646,7 +1646,7 @@ static void draw_tab_overlay_pass(struct wlr_render_pass *pass) { int row = 0; for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *app = server.apps[i]; + struct kick_app *app = server.apps[i]; if (!app_overlay_row(app)) continue; const char *title = app_row_title(app); char fallback[16]; @@ -1705,7 +1705,7 @@ static void swapchain_resize(int width, int height) { } server.swapchain = wlr_swapchain_create(server.allocator, width, height, &fmt); if (!server.swapchain) - fprintf(stderr, "tabbed-wlroots: swapchain create failed at %dx%d\n", + fprintf(stderr, "kick: swapchain create failed at %dx%d\n", width, height); } @@ -1731,7 +1731,7 @@ static void output_resize(int width, int height) { fullscreen the fullscreen configure already sizes clients to the output, so skip the maximize request to avoid state churn. */ for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *app = server.apps[i]; + struct kick_app *app = server.apps[i]; if (!app->toplevel) continue; if (!server.clients_fullscreen) wlr_xdg_toplevel_set_maximized(app->toplevel, true); @@ -1776,16 +1776,16 @@ static void handle_new_output(struct wl_listener *listener, void *data) { struct wlr_output *output = data; /* Standalone (multi-monitor allowed at the wlroots layer): drive only - the first output with the tabbed canvas, like the headless nested + the first output with the kick canvas, like the headless nested single output. Later outputs are left disabled. */ if (server.standalone && standalone_output_count++ > 0) { - tabbed_log(TABBED_LOG_INFO, + kick_log(KICK_LOG_INFO, "standalone: extra output ignored (first output only)\n"); return; } if (!wlr_output_init_render(output, server.allocator, server.renderer)) { - fprintf(stderr, "tabbed-wlroots: output init_render failed\n"); + fprintf(stderr, "kick: output init_render failed\n"); return; } wlr_output_create_global(output, server.wl_display); @@ -1849,7 +1849,7 @@ server.output = output; } } if (!mode) { - fprintf(stderr, "tabbed-wlroots: no %dx%d", + fprintf(stderr, "kick: no %dx%d", mode_req_w, mode_req_h); if (mode_req_refresh > 0) fprintf(stderr, "@%u.%03u", mode_req_refresh / 1000, @@ -1923,7 +1923,7 @@ server.output = output; The scan stops at the array ends -- it never wraps -- so the reflow after a slot is removed matches the old first/last-tab behavior. NULL when `app` is the only live slot. */ -static struct tabbed_app *pick_successor(struct tabbed_app *app, +static struct kick_app *pick_successor(struct kick_app *app, int prefer_right) { if (!app) return NULL; int died = app_index(app); @@ -1952,7 +1952,7 @@ static struct tabbed_app *pick_successor(struct tabbed_app *app, defends active_app against a slot that was somehow still on it. */ static void remove_app(int idx) { if (idx < 0 || idx >= server.num_apps) return; - struct tabbed_app *dead = server.apps[idx]; + struct kick_app *dead = server.apps[idx]; if (server.active_app == dead) server.active_app = NULL; for (int i = 0; i < server.num_apps; i++) @@ -1979,7 +1979,7 @@ static void remove_app(int idx) { static void handle_toplevel_destroy(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_app *app = wl_container_of(listener, app, destroy); + struct kick_app *app = wl_container_of(listener, app, destroy); app->toplevel = NULL; app->tree = NULL; @@ -2020,7 +2020,7 @@ static void handle_toplevel_destroy(struct wl_listener *listener, void *data) { /* Prefer the neighbor to the left (index died-1); if this is the first tab, fall through to the right-side neighbor so the tab that was second becomes the new leftmost. */ - struct tabbed_app *succ = pick_successor(app, -1); + struct kick_app *succ = pick_successor(app, -1); if (succ) { set_active_app(succ); } else { @@ -2036,7 +2036,7 @@ static void handle_toplevel_destroy(struct wl_listener *listener, void *data) { } /* Grace period after the Alt+Delete SIGTERM before SIGKILL escalation. */ -#define TABBED_CLOSE_ESCALATE_MS 150 +#define KICK_CLOSE_ESCALATE_MS 150 /* Escalate an Alt+Delete close to SIGKILL if the client ignored the SIGTERM and its toplevel is still up. Live slots are removed at toplevel destroy @@ -2045,7 +2045,7 @@ static void handle_toplevel_destroy(struct wl_listener *listener, void *data) { toplevel whose destroy would reap the slot, so its removal happens here, right after the SIGKILL. */ static int close_tab_escalate(void *data) { - struct tabbed_app *app = data; + struct kick_app *app = data; if (app->closing && app_killable(app)) kill_app(app, SIGKILL); if (app->close_timer) { @@ -2066,7 +2066,7 @@ static int close_tab_escalate(void *data) { escalation; a closing last tab tears the session down here, since nothing else will. */ static void close_active_tab(void) { - struct tabbed_app *app = server.active_app; + struct kick_app *app = server.active_app; if (!app || !app_killable(app)) return; pid_t g = app_signal_group(app); pid_t shown = (g > 0 && g != getpgid(0)) ? g : app->client_pid; @@ -2080,12 +2080,12 @@ static void close_active_tab(void) { if (!app->toplevel) app->pending_claim = false; - struct tabbed_app *succ = pick_successor(app, +1); + struct kick_app *succ = pick_successor(app, +1); if (succ) { set_active_app(succ); } else { /* Last live tab: tear the session down now. */ - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: closing tab %d (pid %d)\n", + kick_log(KICK_LOG_INFO, "kick: closing tab %d (pid %d)\n", died, (int)shown); if (host.toplevel) xdg_toplevel_destroy(host.toplevel); if (host.surface) wl_surface_destroy(host.surface); @@ -2094,17 +2094,17 @@ static void close_active_tab(void) { } kill_app(app, SIGTERM); - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: closing tab %d (pid %d)\n", + kick_log(KICK_LOG_INFO, "kick: closing tab %d (pid %d)\n", died, (int)shown); app->close_timer = wl_event_loop_add_timer(server.loop, close_tab_escalate, app); if (app->close_timer) - wl_event_source_timer_update(app->close_timer, TABBED_CLOSE_ESCALATE_MS); + wl_event_source_timer_update(app->close_timer, KICK_CLOSE_ESCALATE_MS); } static void handle_request_maximize(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_app *app = wl_container_of(listener, app, request_maximize); + struct kick_app *app = wl_container_of(listener, app, request_maximize); struct wlr_xdg_toplevel *toplevel = app->toplevel; if (toplevel->base->initialized) wlr_xdg_toplevel_set_maximized(toplevel, true); @@ -2112,7 +2112,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) { static void handle_request_fullscreen(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_app *app = wl_container_of(listener, app, request_fullscreen); + struct kick_app *app = wl_container_of(listener, app, request_fullscreen); struct wlr_xdg_toplevel *toplevel = app->toplevel; if (!toplevel->base->initialized) return; /* wlroots 0.19 emits request_fullscreen with NULL data; the direction @@ -2121,7 +2121,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) host window, and an un-fullscreen client puts it back. */ bool fs = toplevel->requested.fullscreen; wlr_xdg_toplevel_set_fullscreen(toplevel, fs); - tabbed_log(TABBED_LOG_INFO, "client fullscreen=%d\n", fs); + kick_log(KICK_LOG_INFO, "client fullscreen=%d\n", fs); if (host.toplevel) { if (fs) xdg_toplevel_set_fullscreen(host.toplevel, NULL); @@ -2134,9 +2134,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) from host_xdg_toplevel_configure when that state actually changes. */ static void clients_set_fullscreen(bool fs) { server.clients_fullscreen = fs; - tabbed_log(TABBED_LOG_INFO, "clients fullscreen=%d\n", fs); + kick_log(KICK_LOG_INFO, "clients fullscreen=%d\n", fs); for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *app = server.apps[i]; + struct kick_app *app = server.apps[i]; if (!app->toplevel || !app->toplevel->base->initialized) continue; wlr_xdg_toplevel_set_fullscreen(app->toplevel, fs); if (!fs) { @@ -2159,7 +2159,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { (void)listener; (void)data; } -static void position_toplevel(struct tabbed_app *app) { +static void position_toplevel(struct kick_app *app) { if (!app || !app->tree) return; /* CSD clients (foot/kitty) reserve a titlebar gutter above their content, which we don't paint, so it shows as a dark bar and their @@ -2176,7 +2176,7 @@ static void position_toplevel(struct tabbed_app *app) { static void handle_toplevel_commit(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_app *app = wl_container_of(listener, app, commit); + struct kick_app *app = wl_container_of(listener, app, commit); struct wlr_xdg_toplevel *toplevel = app->toplevel; if (toplevel->base->initial_commit) { wlr_xdg_toplevel_set_maximized(toplevel, true); @@ -2199,8 +2199,8 @@ static void handle_toplevel_commit(struct wl_listener *listener, void *data) { last_logged = cbuf; bool is_dma = wlr_buffer_get_dmabuf(cbuf, &dma); bool node_on = app->tree ? app->tree->node.enabled : false; - if (tabbed_log_level() >= TABBED_LOG_DEBUG) { - tabbed_log(TABBED_LOG_DEBUG, "[diag] commit app=%d geom=%dx%d+%d+%d " + if (kick_log_level() >= KICK_LOG_DEBUG) { + kick_log(KICK_LOG_DEBUG, "[diag] commit app=%d geom=%dx%d+%d+%d " "buf=%dx%d dma=%d%s node_enabled=%d active=%d\n", app_index(app), toplevel->base->geometry.width, @@ -2214,14 +2214,14 @@ static void handle_toplevel_commit(struct wl_listener *listener, void *data) { node_on, server.active_app == app); if (is_dma) { - tabbed_log(TABBED_LOG_DEBUG, "[diag] dmabuf planes=%d " + kick_log(KICK_LOG_DEBUG, "[diag] dmabuf planes=%d " "format=0x%x mod=0x%llx\n", dma.n_planes, dma.format, (unsigned long long)dma.modifier); } } if (!is_dma) { - /* shm buffer: flag for TABBED_AUTODUMP; at debug level also count + /* shm buffer: flag for KICK_AUTODUMP; at debug level also count non-black pixels and save the client's own buffer so we can tell "client painted nothing" from "we failed to import". */ void *data; @@ -2231,7 +2231,7 @@ static void handle_toplevel_commit(struct wl_listener *listener, void *data) { cbuf, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride)) { client_dumped = true; - if (tabbed_log_level() >= TABBED_LOG_DEBUG) { + if (kick_log_level() >= KICK_LOG_DEBUG) { int bw = cbuf->width, bh = cbuf->height; unsigned long nonblack = 0, lum = 0; unsigned char *p = data; @@ -2244,7 +2244,7 @@ static void handle_toplevel_commit(struct wl_listener *listener, void *data) { if (v > 12) nonblack++; } } - tabbed_log(TABBED_LOG_DEBUG, "[diag] shm fmt=0x%x " + kick_log(KICK_LOG_DEBUG, "[diag] shm fmt=0x%x " "nonblack=%lu/%lu mean=%lu\n", fmt, nonblack, (unsigned long)bw * bh, lum / ((unsigned long)bw * bh + 1)); @@ -2264,7 +2264,7 @@ static void handle_toplevel_commit(struct wl_listener *listener, void *data) { } } fclose(cf); - tabbed_log(TABBED_LOG_DEBUG, "[diag] client buffer " + kick_log(KICK_LOG_DEBUG, "[diag] client buffer " "-> %s\n", cpath); } } @@ -2277,7 +2277,7 @@ static void handle_toplevel_commit(struct wl_listener *listener, void *data) { /* Insert `app` in the slot order immediately after `anchor`, shifting the slots after it right; append at the far right if anchor is NULL or no longer present. */ -static void insert_app_after(struct tabbed_app *app, struct tabbed_app *anchor) { +static void insert_app_after(struct kick_app *app, struct kick_app *anchor) { int at = server.num_apps; if (anchor) for (int i = 0; i < server.num_apps; i++) @@ -2299,7 +2299,7 @@ static void insert_app_after(struct tabbed_app *app, struct tabbed_app *anchor) client opening a second toplevel) is the depth-0 case. Walk /proc//stat ppid links, capped, to find the owning tab; NULL if the client is not descended from any tab. */ -static struct tabbed_app *sub_window_owner(pid_t cpid) { +static struct kick_app *sub_window_owner(pid_t cpid) { if (cpid <= 1) return NULL; pid_t p = cpid; @@ -2333,10 +2333,10 @@ static struct tabbed_app *sub_window_owner(pid_t cpid) { static void handle_toplevel_map(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_app *app = wl_container_of(listener, app, map); + struct kick_app *app = wl_container_of(listener, app, map); struct wlr_xdg_toplevel *toplevel = app->toplevel; - if (tabbed_log_level() >= TABBED_LOG_DEBUG) - tabbed_log(TABBED_LOG_DEBUG, "[diag] map app=%d\n", app_index(app)); + if (kick_log_level() >= KICK_LOG_DEBUG) + kick_log(KICK_LOG_DEBUG, "[diag] map app=%d\n", app_index(app)); /* A new tab never steals focus on its own. The exceptions: a Alt+Shift+T terminal (add_tab), a sub-window whose parent tab is the @@ -2377,7 +2377,7 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { wl_client_get_credentials(toplevel->base->client->client, &cpid, NULL, NULL); - struct tabbed_app *app = NULL; + struct kick_app *app = NULL; /* A slot awaiting its toplevel -- an unclaimed command-line command or a fresh Alt+Shift+T terminal -- belongs to exactly ONE client: the one WE launched for it. launch_client() runs each command in its own @@ -2389,7 +2389,7 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { can't steal a still-loading tab's position. */ pid_t pgid = cpid > 0 ? getpgid(cpid) : -1; for (int i = 0; i < server.num_apps && !app; i++) { - struct tabbed_app *a = server.apps[i]; + struct kick_app *a = server.apps[i]; if (a->toplevel || !a->pending_claim) continue; if (a->pid > 0 && a->pid == pgid) app = a; @@ -2401,16 +2401,16 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { launch_all_cli); their clients match the pending loop above, and only then. */ if (!app && cpid > 0) { - struct tabbed_app *owner = sub_window_owner(cpid); + struct kick_app *owner = sub_window_owner(cpid); if (owner) { if (apps_ensure_cap(server.num_apps + 1) != 0) return; - struct tabbed_app *sub = calloc(1, sizeof(*sub)); + struct kick_app *sub = calloc(1, sizeof(*sub)); if (!sub) return; sub->pid = -1; sub->cmd = NULL; sub->origin = ORIGIN_SUB; sub->parent_app = owner; - struct tabbed_app *pa = toplevel->parent + struct kick_app *pa = toplevel->parent ? app_for_toplevel(toplevel->parent) : NULL; insert_app_after(sub, pa ? pa : owner); app = sub; @@ -2423,7 +2423,7 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { through to the ORIGIN_EXTERNAL append below. */ if (!app) for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *a = server.apps[i]; + struct kick_app *a = server.apps[i]; if (!a->toplevel && !a->pending_claim && !a->closing) { app = a; break; @@ -2435,12 +2435,12 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { reachable via tab cycling, right after the tab that created it (protocol parent, else the active tab); far right if unidentified. */ if (apps_ensure_cap(server.num_apps + 1) != 0) return; - struct tabbed_app *extra = calloc(1, sizeof(*extra)); + struct kick_app *extra = calloc(1, sizeof(*extra)); if (!extra) return; extra->pid = -1; extra->cmd = NULL; extra->origin = ORIGIN_EXTERNAL; - struct tabbed_app *pa = toplevel->parent + struct kick_app *pa = toplevel->parent ? app_for_toplevel(toplevel->parent) : NULL; if (!pa) pa = app_for_toplevel(active_toplevel()); @@ -2469,7 +2469,7 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { app->client_pid = cpid; pid_t cpg = cpid > 0 ? getpgid(cpid) : -1; app->pgid = (cpg > 0 && cpg != getpgid(0)) ? cpg : -1; - tabbed_log(TABBED_LOG_INFO, "[claim] app=%d pid=%d\n", + kick_log(KICK_LOG_INFO, "[claim] app=%d pid=%d\n", app_index(app), (int)cpid); app->destroy.notify = handle_toplevel_destroy; @@ -2495,7 +2495,7 @@ static void handle_new_toplevel(struct wl_listener *listener, void *data) { /* ===================== Tab management ===================== */ -static struct tabbed_app *app_for_toplevel(struct wlr_xdg_toplevel *toplevel) { +static struct kick_app *app_for_toplevel(struct wlr_xdg_toplevel *toplevel) { if (!toplevel) return NULL; for (int i = 0; i < server.num_apps; i++) if (server.apps[i]->toplevel == toplevel) @@ -2503,14 +2503,14 @@ static struct tabbed_app *app_for_toplevel(struct wlr_xdg_toplevel *toplevel) { return NULL; } -static int app_index(struct tabbed_app *app) { +static int app_index(struct kick_app *app) { for (int i = 0; i < server.num_apps; i++) if (server.apps[i] == app) return i; return -1; } -struct tabbed_popup { +struct kick_popup { struct wlr_xdg_surface *xdg_surface; struct wlr_scene_tree *scene; struct wl_listener commit; @@ -2539,7 +2539,7 @@ static void popup_usable_box(struct wlr_box *box) { each popup under its parent's tree. */ static void popup_handle_commit(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_popup *tp = wl_container_of(listener, tp, commit); + struct kick_popup *tp = wl_container_of(listener, tp, commit); struct wlr_xdg_surface *xdg_surface = tp->xdg_surface; /* The client cannot map/render the popup until it receives its initial configure, which wlroots only sends via wlr_xdg_popup_unconstrain_from @@ -2554,7 +2554,7 @@ static void popup_handle_commit(struct wl_listener *listener, void *data) { static void popup_handle_reposition(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_popup *tp = wl_container_of(listener, tp, reposition); + struct kick_popup *tp = wl_container_of(listener, tp, reposition); if (tp->xdg_surface->popup) { struct wlr_box box; popup_usable_box(&box); @@ -2564,7 +2564,7 @@ static void popup_handle_reposition(struct wl_listener *listener, void *data) { static void popup_handle_destroy(struct wl_listener *listener, void *data) { (void)data; - struct tabbed_popup *tp = wl_container_of(listener, tp, destroy); + struct kick_popup *tp = wl_container_of(listener, tp, destroy); wl_list_remove(&tp->commit.link); wl_list_remove(&tp->destroy.link); wl_list_remove(&tp->reposition.link); @@ -2574,7 +2574,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { static void create_popup(struct wlr_xdg_popup *popup, struct wlr_scene_tree *parent_tree) { struct wlr_xdg_surface *xdg_surface = popup->base; - struct tabbed_popup *tp = calloc(1, sizeof(*tp)); + struct kick_popup *tp = calloc(1, sizeof(*tp)); if (!tp) return; tp->xdg_surface = xdg_surface; tp->scene = wlr_scene_xdg_surface_create(parent_tree, xdg_surface); @@ -2603,10 +2603,10 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { wlr_xdg_surface_try_from_wlr_surface(popup->parent); if (parent) { if (parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - struct tabbed_app *app = app_for_toplevel(parent->toplevel); + struct kick_app *app = app_for_toplevel(parent->toplevel); if (app) parent_tree = app->tree; } else if (parent->role == WLR_XDG_SURFACE_ROLE_POPUP) { - struct tabbed_popup *tp = parent->data; + struct kick_popup *tp = parent->data; if (tp) parent_tree = tp->scene; } } @@ -2620,10 +2620,10 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { Called with the same app as already active only to promote it black -> mapped (the one case with something still to do), so callers that want a true no-op must guard first. */ -static void set_active_app(struct tabbed_app *app) { +static void set_active_app(struct kick_app *app) { if (!app) return; - struct tabbed_app *old = server.active_app; + struct kick_app *old = server.active_app; if (old && old != app && old->toplevel) { if (old->tree) wlr_scene_node_set_enabled(&old->tree->node, false); @@ -2636,13 +2636,13 @@ static void set_active_app(struct tabbed_app *app) { position_toplevel(app); if (app->tree) wlr_scene_node_set_enabled(&app->tree->node, true); - if (tabbed_log_level() >= TABBED_LOG_DEBUG) - tabbed_log(TABBED_LOG_DEBUG, "[diag] active app=%d surface=%dx%d " + if (kick_log_level() >= KICK_LOG_DEBUG) + kick_log(KICK_LOG_DEBUG, "[diag] active app=%d surface=%dx%d " "node on\n", app_index(app), app->toplevel->base->surface->current.width, app->toplevel->base->surface->current.height); - } else if (tabbed_log_level() >= TABBED_LOG_DEBUG) { - tabbed_log(TABBED_LOG_DEBUG, "[diag] active slot=%d (black, awaiting map)\n", + } else if (kick_log_level() >= KICK_LOG_DEBUG) { + kick_log(KICK_LOG_DEBUG, "[diag] active slot=%d (black, awaiting map)\n", app_index(app)); } @@ -2662,7 +2662,7 @@ static void set_active_app(struct tabbed_app *app) { } static void set_active_surface(struct wlr_xdg_toplevel *toplevel) { - struct tabbed_app *app = app_for_toplevel(toplevel); + struct kick_app *app = app_for_toplevel(toplevel); if (!app) return; /* Promoting the already-active black tab to mapped is the one same-app call that must still run; everything else that's a true no-op returns @@ -2743,7 +2743,7 @@ static void reorder_active_tab(int dir) { tabs this is just a swap, but when `neighbor` wraps around to the far end (from is first/last of the live list) the other live tabs must all shuffle one place rather than staying put. */ - struct tabbed_app *moved = server.apps[from]; + struct kick_app *moved = server.apps[from]; if (neighbor < from) { memmove(&server.apps[neighbor + 1], &server.apps[neighbor], (size_t)(from - neighbor) * sizeof(*server.apps)); @@ -2754,7 +2754,7 @@ static void reorder_active_tab(int dir) { server.apps[neighbor] = moved; } - tabbed_log(TABBED_LOG_INFO, "[reorder] app=%d dir=%d\n", + kick_log(KICK_LOG_INFO, "[reorder] app=%d dir=%d\n", neighbor, dir); needs_redraw = true; if (server.standalone) @@ -2762,8 +2762,8 @@ static void reorder_active_tab(int dir) { } /* Fixed keybind repeat: first repeat after 600ms, then every 40ms (25Hz). */ -#define TABBED_REPEAT_DELAY_MS 600 -#define TABBED_REPEAT_INTERVAL_MS 40 +#define KICK_REPEAT_DELAY_MS 600 +#define KICK_REPEAT_INTERVAL_MS 40 static void kbd_repeat_cancel(void) { if (host.repeat_timer) { @@ -2783,7 +2783,7 @@ static int kbd_repeat_cb(void *data) { cycle_tab(host.repeat_dir); if (host.repeat_timer) wl_event_source_timer_update(host.repeat_timer, - TABBED_REPEAT_INTERVAL_MS); + KICK_REPEAT_INTERVAL_MS); return 0; } @@ -2794,7 +2794,7 @@ static void kbd_repeat_start(int key, int dir, int kind) { host.repeat_kind = kind; host.repeat_timer = wl_event_loop_add_timer(server.loop, kbd_repeat_cb, NULL); if (host.repeat_timer) - wl_event_source_timer_update(host.repeat_timer, TABBED_REPEAT_DELAY_MS); + wl_event_source_timer_update(host.repeat_timer, KICK_REPEAT_DELAY_MS); } /* ===================== Clipboard bridge implementation ===================== */ @@ -2908,7 +2908,7 @@ static void bridge_clear_nested(void) { /* ---------------- text prefetch: serve pastes from a buffered copy -------- */ -#define TABBED_PREFETCH_MAX (16 * 1024 * 1024) +#define KICK_PREFETCH_MAX (16 * 1024 * 1024) static void bridge_prefetch_cancel(void) { if (bridge.prefetch_src) { @@ -2932,10 +2932,10 @@ static bool bridge_prefetch_drain(int fd) { for (;;) { size_t room = bridge.prefetch_cap - bridge.prefetch_len; if (bridge.prefetch_len + 4096 > bridge.prefetch_cap && - bridge.prefetch_cap < TABBED_PREFETCH_MAX) { + bridge.prefetch_cap < KICK_PREFETCH_MAX) { size_t ncap = bridge.prefetch_cap ? bridge.prefetch_cap * 2 : 8192; - if (ncap > TABBED_PREFETCH_MAX) - ncap = TABBED_PREFETCH_MAX; + if (ncap > KICK_PREFETCH_MAX) + ncap = KICK_PREFETCH_MAX; char *nb = realloc(bridge.prefetch_buf, ncap); if (nb) { bridge.prefetch_buf = nb; @@ -3116,7 +3116,7 @@ static void bridge_dc_device_finished(void *data, zwlr_data_control_device_v1_destroy(bridge.dc_device); bridge.dc_device = NULL; } - tabbed_log(TABBED_LOG_INFO, "clipboard bridge: host data-control " + kick_log(KICK_LOG_INFO, "clipboard bridge: host data-control " "finished; falling back to %s\n", bridge.backend == BRIDGE_BACKEND_WL_DATA_DEVICE ? "focus-based wl_data_device" : "none"); @@ -3302,7 +3302,7 @@ static void bridge_host_set_selection(struct wlr_data_source *src) { } if (!bridge.kbd_serial) { bridge.host_set_pending = true; - tabbed_log(TABBED_LOG_INFO, "clipboard bridge: no host keyboard " + kick_log(KICK_LOG_INFO, "clipboard bridge: no host keyboard " "serial yet; deferring host set_selection until focus\n"); return; } @@ -3359,7 +3359,7 @@ static void bridge_attach_seat(void) { static void bridge_init(void) { if (!host.seat) { - tabbed_log(TABBED_LOG_INFO, "clipboard bridge: no host seat; disabled\n"); + kick_log(KICK_LOG_INFO, "clipboard bridge: no host seat; disabled\n"); return; } /* Re-entrant: drop any objects bound to a previous host seat so a runtime @@ -3385,14 +3385,14 @@ static void bridge_init(void) { zwlr_data_control_device_v1_add_listener(bridge.dc_device, &bridge_dc_listener, NULL); bridge.backend = BRIDGE_BACKEND_DATA_CONTROL; - tabbed_log(TABBED_LOG_INFO, "clipboard bridge: host data-control backend\n"); + kick_log(KICK_LOG_INFO, "clipboard bridge: host data-control backend\n"); } else if (bridge.dd) { bridge.backend = BRIDGE_BACKEND_WL_DATA_DEVICE; - tabbed_log(TABBED_LOG_INFO, "clipboard bridge: focus-based wl_data_device " + kick_log(KICK_LOG_INFO, "clipboard bridge: focus-based wl_data_device " "backend (host lacks wlr-data-control; host->nested sync needs " "focus)\n"); } else { - tabbed_log(TABBED_LOG_INFO, "clipboard bridge: no host clipboard path\n"); + kick_log(KICK_LOG_INFO, "clipboard bridge: no host clipboard path\n"); } } @@ -3488,7 +3488,7 @@ static void host_registry_global_remove(void *data, struct wl_registry *registry re-created when the compositor advertises a new seat. Other globals we bind (compositor, xdg_wm_base, ...) are process-lifetime. */ if (host.seat_name && name == host.seat_name) { - tabbed_log(TABBED_LOG_DEBUG, "[seat] global %u removed\n", name); + kick_log(KICK_LOG_DEBUG, "[seat] global %u removed\n", name); host.seat_name = 0; host.seat = NULL; host.keyboard = NULL; @@ -3558,7 +3558,7 @@ static void host_xdg_toplevel_configure(void *data, struct xdg_toplevel *t, /* Mirror the host window's state onto the clients: fullscreen begets fullscreen, anything else begets maximized. */ if (host.fullscreen != server.clients_fullscreen) { - tabbed_log(TABBED_LOG_INFO, "host fullscreen=%d\n", host.fullscreen); + kick_log(KICK_LOG_INFO, "host fullscreen=%d\n", host.fullscreen); clients_set_fullscreen(host.fullscreen); } if (width > 0 && height > 0) @@ -3568,7 +3568,7 @@ static void host_xdg_toplevel_configure(void *data, struct xdg_toplevel *t, static void host_xdg_toplevel_close(void *data, struct xdg_toplevel *t) { (void)data; (void)t; - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: window closed\n"); + kick_log(KICK_LOG_INFO, "kick: window closed\n"); shutdown_cleanup(); exit(0); } @@ -3583,7 +3583,7 @@ static void host_decoration_configure(void *data, uint32_t mode) { (void)data; (void)dec; - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: host decoration mode=%u (%s)\n", + kick_log(KICK_LOG_INFO, "kick: host decoration mode=%u (%s)\n", mode, mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE ? "server-side" : "client-side"); @@ -3611,7 +3611,7 @@ static void xkb_state_reload(void) server.xkb_prefix_mod = xkb_keymap_mod_get_index(server.xkb_keymap, tab_prefix == PREFIX_SUPER ? XKB_PREFIX_MOD4_NAME : XKB_MOD_NAME_ALT); - tabbed_log(TABBED_LOG_DEBUG, "tabbed-wlroots: prefix modifier index=%u " + kick_log(KICK_LOG_DEBUG, "kick: prefix modifier index=%u " "(%s)\n", (unsigned)server.xkb_prefix_mod, tab_prefix == PREFIX_SUPER ? "Super/Mod4" : "Alt"); } @@ -3624,7 +3624,7 @@ static void host_kbd_keymap(void *data, struct wl_keyboard *kbd, uint32_t format close(fd); return; } - tabbed_log(TABBED_LOG_DEBUG, "tabbed-wlroots: host keymap: format=%u size=%u\n", + kick_log(KICK_LOG_DEBUG, "kick: host keymap: format=%u size=%u\n", format, size); /* The keymap is an shm file (size includes the trailing NUL), so mmap it @@ -3651,8 +3651,8 @@ static void host_kbd_keymap(void *data, struct wl_keyboard *kbd, uint32_t format } buf[total] = '\0'; if (total < size) - tabbed_log(TABBED_LOG_DEBUG, - "tabbed-wlroots: host keymap: short read %zu/%u bytes\n", + kick_log(KICK_LOG_DEBUG, + "kick: host keymap: short read %zu/%u bytes\n", total, size); } @@ -3664,17 +3664,17 @@ static void host_kbd_keymap(void *data, struct wl_keyboard *kbd, uint32_t format xkb_keymap_unref(server.xkb_keymap); server.xkb_keymap = km; xkb_state_reload(); - tabbed_log(TABBED_LOG_DEBUG, "tabbed-wlroots: host keymap parsed OK\n"); + kick_log(KICK_LOG_DEBUG, "kick: host keymap parsed OK\n"); } else { - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: failed to parse host " + kick_log(KICK_LOG_INFO, "kick: failed to parse host " "keymap (%u bytes); keeping fallback keymap\n", size); - if (tabbed_log_level() >= TABBED_LOG_DEBUG) { + if (kick_log_level() >= KICK_LOG_DEBUG) { char hex[129]; size_t n = total < 64 ? total : 64; for (size_t i = 0; i < n; i++) snprintf(hex + i * 2, sizeof(hex) - i * 2, "%02x", (unsigned char)buf[i]); - tabbed_log(TABBED_LOG_DEBUG, "tabbed-wlroots: keymap head (%zu/%u " + kick_log(KICK_LOG_DEBUG, "kick: keymap head (%zu/%u " "bytes): %s\n", n, size, hex); } } @@ -3707,7 +3707,7 @@ static void host_kbd_enter(void *data, struct wl_keyboard *kbd, uint32_t serial, bridge.host_set_pending = false; bridge_host_set_selection(server.seat->selection_source); } - tabbed_log(TABBED_LOG_DEBUG, "[kbd] enter surface=%p serial=%u active=%p\n", + kick_log(KICK_LOG_DEBUG, "[kbd] enter surface=%p serial=%u active=%p\n", (void *)surface, serial, (void *)active_toplevel()); struct wlr_xdg_toplevel *tl = active_toplevel(); if (tl) @@ -3720,7 +3720,7 @@ static void host_kbd_leave(void *data, struct wl_keyboard *kbd, uint32_t serial, struct wl_surface *surface) { (void)data; (void)kbd; (void)serial; (void)surface; - tabbed_log(TABBED_LOG_DEBUG, "[kbd] leave surface=%p serial=%u\n", + kick_log(KICK_LOG_DEBUG, "[kbd] leave surface=%p serial=%u\n", (void *)surface, serial); wlr_seat_keyboard_notify_clear_focus(server.seat); } @@ -3735,7 +3735,7 @@ static void dump_scene_buffer(struct wlr_buffer *buf) { size_t stride; if (!wlr_buffer_begin_data_ptr_access(buf, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { - tabbed_log(TABBED_LOG_INFO, "[dump] scene buffer not CPU-readable " + kick_log(KICK_LOG_INFO, "[dump] scene buffer not CPU-readable " "(%dx%d)\n", buf->width, buf->height); return; } @@ -3753,7 +3753,7 @@ static void dump_scene_buffer(struct wlr_buffer *buf) { if (v > 12) nonblack++; } } - tabbed_log(TABBED_LOG_INFO, "[dump] scene %dx%d fmt=0x%x " + kick_log(KICK_LOG_INFO, "[dump] scene %dx%d fmt=0x%x " "nonblack=%lu/%lu mean=%lu\n", w, h, format, nonblack, (unsigned long)w * h, lum / ((unsigned long)w * h + 1)); char path[64]; @@ -3772,7 +3772,7 @@ static void dump_scene_buffer(struct wlr_buffer *buf) { } } fclose(f); - tabbed_log(TABBED_LOG_INFO, "[dump] scene buffer -> %s (%dx%d, " + kick_log(KICK_LOG_INFO, "[dump] scene buffer -> %s (%dx%d, " "fmt=0x%x)\n", path, w, h, format); } wlr_buffer_end_data_ptr_access(buf); @@ -3796,7 +3796,7 @@ static void dump_host_back(void) { lum += v; if (v > 12) nonblack++; } - tabbed_log(TABBED_LOG_INFO, "[dump] host %dx%d nonblack=%lu/%lu mean=%lu\n", + kick_log(KICK_LOG_INFO, "[dump] host %dx%d nonblack=%lu/%lu mean=%lu\n", w, h, nonblack, (unsigned long)w * h, lum / ((unsigned long)w * h + 1)); char path[64]; @@ -3813,7 +3813,7 @@ static void dump_host_back(void) { } } fclose(f); - tabbed_log(TABBED_LOG_INFO, "[dump] host back buffer -> %s (%dx%d)\n", + kick_log(KICK_LOG_INFO, "[dump] host back buffer -> %s (%dx%d)\n", path, w, h); } free(px); @@ -3851,7 +3851,7 @@ static void dump_standalone_buffer(struct wlr_buffer *buf) { if (!wlr_buffer_begin_data_ptr_access(buf, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { free(px); - tabbed_log(TABBED_LOG_INFO, + kick_log(KICK_LOG_INFO, "[dump] standalone buffer not CPU-readable\n"); return; } @@ -3867,7 +3867,7 @@ static void dump_standalone_buffer(struct wlr_buffer *buf) { lum += v; if (v > 12) nonblack++; } - tabbed_log(TABBED_LOG_INFO, "[dump] host %dx%d nonblack=%lu/%lu mean=%lu\n", + kick_log(KICK_LOG_INFO, "[dump] host %dx%d nonblack=%lu/%lu mean=%lu\n", w, h, nonblack, (unsigned long)w * h, lum / ((unsigned long)w * h + 1)); char path[64]; @@ -3885,17 +3885,17 @@ static void dump_standalone_buffer(struct wlr_buffer *buf) { } } fclose(f); - tabbed_log(TABBED_LOG_INFO, "[dump] host back buffer -> %s (%dx%d)\n", + kick_log(KICK_LOG_INFO, "[dump] host back buffer -> %s (%dx%d)\n", path, w, h); if (server.cursor) - tabbed_log(TABBED_LOG_INFO, + kick_log(KICK_LOG_INFO, "[dump] cursor at (%f,%f)\n", server.cursor->x, server.cursor->y); } free(px); dump_seq++; } -/* TABBED_SYNTH_INPUT=1: ignore the real host keyboard entirely and accept +/* KICK_SYNTH_INPUT=1: ignore the real host keyboard entirely and accept input only from the stdin event feed (the test/driver channel). The host keyboard listener stays attached (its enter/leave events still drive the clipboard bridge), but key and modifier events from the real host are @@ -4015,7 +4015,7 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state, update_overlay_visible(alt); char symbuf[32]; xkb_keysym_get_name(sym, symbuf, sizeof(symbuf)); - tabbed_log(TABBED_LOG_DEBUG, + kick_log(KICK_LOG_DEBUG, "[kbd] key=%u state=%u sym=%s ctrl=%d alt=%d repeat_key=%u\n", key, state, sym ? symbuf : "-", (mods_depressed & (1u << 2)) != 0, alt, host.repeat_key); @@ -4028,8 +4028,8 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state, sym <= XKB_KEY_XF86Switch_VT_12) { if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1; - tabbed_log(TABBED_LOG_INFO, - "tabbed-wlroots: vt switch -> %u\n", vt); + kick_log(KICK_LOG_INFO, + "kick: vt switch -> %u\n", vt); wlr_session_change_vt(server.session, vt); } return true; @@ -4120,8 +4120,8 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state, if (!term_key_held) { term_key_held = true; if (!cmd_in_path(term_cmd)) { - tabbed_log(TABBED_LOG_INFO, - "tabbed-wlroots: '%s' not found in PATH; " + kick_log(KICK_LOG_INFO, + "kick: '%s' not found in PATH; " "no terminal opened (set $TERMINAL)\n", term_cmd); } else { @@ -4343,7 +4343,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { kd->destroy.notify = standalone_kbd_destroy; wl_signal_add(&kb->base.events.destroy, &kd->destroy); wl_list_insert(server.kbdevs.prev, &kd->link); - tabbed_log(TABBED_LOG_INFO, "standalone: keyboard '%s'\n", device->name); + kick_log(KICK_LOG_INFO, "standalone: keyboard '%s'\n", device->name); break; } case WLR_INPUT_DEVICE_POINTER: { @@ -4366,7 +4366,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { pd->destroy.notify = standalone_ptr_destroy; wl_signal_add(&ptr->base.events.destroy, &pd->destroy); wl_list_insert(server.ptrdevs.prev, &pd->link); - tabbed_log(TABBED_LOG_INFO, "standalone: pointer '%s'\n", device->name); + kick_log(KICK_LOG_INFO, "standalone: pointer '%s'\n", device->name); break; } default: @@ -4596,30 +4596,30 @@ static void host_seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities) { (void)data; (void)seat; - tabbed_log(TABBED_LOG_DEBUG, "[seat] capabilities=0x%x\n", capabilities); + kick_log(KICK_LOG_DEBUG, "[seat] capabilities=0x%x\n", capabilities); const bool have_kbd = (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0; const bool have_ptr = (capabilities & WL_SEAT_CAPABILITY_POINTER) != 0; if (have_kbd && !host.keyboard) { host.keyboard = wl_seat_get_keyboard(host.seat); if (host.keyboard) { - tabbed_log(TABBED_LOG_DEBUG, "[seat] re-gained keyboard\n"); + kick_log(KICK_LOG_DEBUG, "[seat] re-gained keyboard\n"); wl_keyboard_add_listener(host.keyboard, &host_kbd_listener, NULL); } } else if (!have_kbd && host.keyboard) { wl_keyboard_release(host.keyboard); host.keyboard = NULL; - tabbed_log(TABBED_LOG_DEBUG, "[seat] keyboard capability lost\n"); + kick_log(KICK_LOG_DEBUG, "[seat] keyboard capability lost\n"); } if (have_ptr && !host.pointer) { host.pointer = wl_seat_get_pointer(host.seat); if (host.pointer) { - tabbed_log(TABBED_LOG_DEBUG, "[seat] re-gained pointer\n"); + kick_log(KICK_LOG_DEBUG, "[seat] re-gained pointer\n"); wl_pointer_add_listener(host.pointer, &host_ptr_listener, NULL); } } else if (!have_ptr && host.pointer) { wl_pointer_release(host.pointer); host.pointer = NULL; - tabbed_log(TABBED_LOG_DEBUG, "[seat] pointer capability lost\n"); + kick_log(KICK_LOG_DEBUG, "[seat] pointer capability lost\n"); } } @@ -4631,7 +4631,7 @@ static bool host_init(void) { disp = "wayland-0"; host.display = wl_display_connect(NULL); if (!host.display) { - fprintf(stderr, "tabbed-wlroots: cannot connect to host compositor " + fprintf(stderr, "kick: cannot connect to host compositor " "(WAYLAND_DISPLAY=%s). Run me inside a running Wayland session.\n", disp); return false; @@ -4643,14 +4643,14 @@ static bool host_init(void) { host.registry_synced = true; if (!host.compositor || !host.wm_base) { - fprintf(stderr, "tabbed-wlroots: host lacks compositor/xdg_wm_base\n"); + fprintf(stderr, "kick: host lacks compositor/xdg_wm_base\n"); return false; } host.surface = wl_compositor_create_surface(host.compositor); host.xdg_surface = xdg_wm_base_get_xdg_surface(host.wm_base, host.surface); host.toplevel = xdg_surface_get_toplevel(host.xdg_surface); - xdg_toplevel_set_title(host.toplevel, "tabbed-wlroots"); + xdg_toplevel_set_title(host.toplevel, "kick"); if (host.decoration) { /* Ask the host compositor (labwc) for a server-side title bar, so the nested window always has a host-drawn decoration above our @@ -4676,7 +4676,7 @@ static bool host_init(void) { pfn_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT"); if (!pfn_eglGetPlatformDisplayEXT) { - fprintf(stderr, "tabbed-wlroots: no EGL platform support; " + fprintf(stderr, "kick: no EGL platform support; " "falling back to software rendering\n"); host.egl_ok = false; return true; @@ -4685,13 +4685,13 @@ static bool host_init(void) { host.egl_display = pfn_eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, host.display, NULL); if (host.egl_display == EGL_NO_DISPLAY) { - fprintf(stderr, "tabbed-wlroots: EGL display failed; " + fprintf(stderr, "kick: EGL display failed; " "falling back to software rendering\n"); host.egl_ok = false; return true; } if (!eglInitialize(host.egl_display, NULL, NULL)) { - fprintf(stderr, "tabbed-wlroots: eglInitialize failed; " + fprintf(stderr, "kick: eglInitialize failed; " "falling back to software rendering\n"); host.egl_ok = false; return true; @@ -4711,7 +4711,7 @@ static bool host_init(void) { EGLint ncfg = 0; if (!eglChooseConfig(host.egl_display, config_attribs, &host.egl_config, 1, &ncfg) || ncfg < 1) { - fprintf(stderr, "tabbed-wlroots: no EGL config; software fallback\n"); + fprintf(stderr, "kick: no EGL config; software fallback\n"); host.egl_ok = false; return true; } @@ -4723,7 +4723,7 @@ static bool host_init(void) { host.egl_context = eglCreateContext(host.egl_display, host.egl_config, EGL_NO_CONTEXT, ctx_attribs); if (host.egl_context == EGL_NO_CONTEXT) { - fprintf(stderr, "tabbed-wlroots: EGL context failed; software fallback\n"); + fprintf(stderr, "kick: EGL context failed; software fallback\n"); host.egl_ok = false; return true; } @@ -4734,14 +4734,14 @@ static bool host_init(void) { host.egl_surface = eglCreateWindowSurface(host.egl_display, host.egl_config, (EGLNativeWindowType)host.egl_window, NULL); if (host.egl_surface == EGL_NO_SURFACE) { - fprintf(stderr, "tabbed-wlroots: EGL window surface failed; software fallback\n"); + fprintf(stderr, "kick: EGL window surface failed; software fallback\n"); host.egl_ok = false; return true; } if (!eglMakeCurrent(host.egl_display, host.egl_surface, host.egl_surface, host.egl_context)) { - fprintf(stderr, "tabbed-wlroots: eglMakeCurrent failed; software fallback\n"); + fprintf(stderr, "kick: eglMakeCurrent failed; software fallback\n"); host.egl_ok = false; return true; } @@ -4753,14 +4753,14 @@ static bool host_init(void) { egl_proc("glEGLImageTargetTexture2DOES"); if (!gl_setup()) { - fprintf(stderr, "tabbed-wlroots: GL setup failed; software fallback\n"); + fprintf(stderr, "kick: GL setup failed; software fallback\n"); host.egl_ok = false; return true; } overlay_font_init(); host.egl_ok = true; - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: EGL (GPU) rendering enabled\n"); + kick_log(KICK_LOG_INFO, "kick: EGL (GPU) rendering enabled\n"); return true; } @@ -4793,7 +4793,7 @@ static bool import_scene_buffer(struct wlr_buffer *buf, GLuint tex) { EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer)NULL, att); if (img == EGL_NO_IMAGE_KHR) { - tabbed_log(TABBED_LOG_DEBUG, "[import] eglCreateImageKHR failed " + kick_log(KICK_LOG_DEBUG, "[import] eglCreateImageKHR failed " "(format 0x%x modifier 0x%llx)\n", attrs.format, (unsigned long long)attrs.modifier); return false; @@ -4812,7 +4812,7 @@ static bool import_scene_buffer(struct wlr_buffer *buf, GLuint tex) { size_t stride; if (!wlr_buffer_begin_data_ptr_access(buf, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride)) { - tabbed_log(TABBED_LOG_DEBUG, "[import] buffer is neither dmabuf nor " + kick_log(KICK_LOG_DEBUG, "[import] buffer is neither dmabuf nor " "CPU-readable\n"); return false; } @@ -4825,7 +4825,7 @@ static bool import_scene_buffer(struct wlr_buffer *buf, GLuint tex) { GL_BGRA_EXT, GL_UNSIGNED_BYTE, data); break; default: - tabbed_log(TABBED_LOG_DEBUG, "[import] unsupported CPU fallback format " + kick_log(KICK_LOG_DEBUG, "[import] unsupported CPU fallback format " "0x%x\n", fmt); wlr_buffer_end_data_ptr_access(buf); return false; @@ -4944,7 +4944,7 @@ static void render_standalone(void) { bool rendered = wlr_scene_output_build_state(server.scene_output, &state, &options); if (!rendered || !state.buffer) { - tabbed_log(TABBED_LOG_DEBUG, "[render] build_state failed\n"); + kick_log(KICK_LOG_DEBUG, "[render] build_state failed\n"); wlr_output_state_finish(&state); goto frame_done; } @@ -4969,7 +4969,7 @@ static void render_standalone(void) { } if (!wlr_output_commit_state(server.output, &state)) - tabbed_log(TABBED_LOG_DEBUG, "[render] output commit failed\n"); + kick_log(KICK_LOG_DEBUG, "[render] output commit failed\n"); frame_done: struct timespec now; @@ -4995,7 +4995,7 @@ static void render_and_present(void) { bool rendered = wlr_scene_output_build_state(server.scene_output, &state, &options); if (!rendered || !state.buffer) { - tabbed_log(TABBED_LOG_DEBUG, "[render] build_state failed\n"); + kick_log(KICK_LOG_DEBUG, "[render] build_state failed\n"); wlr_output_state_finish(&state); goto frame_done; } @@ -5003,9 +5003,9 @@ static void render_and_present(void) { /* [diag] What did wlroots composite? A swapchain-sized buffer means we composited the scene; anything else implies direct scanout of a client buffer (which our blit may or may not import). */ - if (tabbed_log_level() >= TABBED_LOG_DEBUG) { + if (kick_log_level() >= KICK_LOG_DEBUG) { struct wlr_output *out = server.output; - tabbed_log(TABBED_LOG_DEBUG, "[diag] frame buffer %dx%d (output %dx%d)\n", + kick_log(KICK_LOG_DEBUG, "[diag] frame buffer %dx%d (output %dx%d)\n", state.buffer->width, state.buffer->height, out ? out->width : 0, out ? out->height : 0); } @@ -5020,7 +5020,7 @@ static void render_and_present(void) { static int autodump = -1; if (autodump < 0) - autodump = getenv("TABBED_AUTODUMP") ? 1 : 0; + autodump = getenv("KICK_AUTODUMP") ? 1 : 0; if (autodump > 0 && client_dumped && --autodump == 0) { dump_scene_req = true; dump_host_req = true; @@ -5029,7 +5029,7 @@ static void render_and_present(void) { blit_scene_buffer(state.buffer); if (!wlr_output_commit_state(server.output, &state)) - tabbed_log(TABBED_LOG_DEBUG, "[render] output commit failed\n"); + kick_log(KICK_LOG_DEBUG, "[render] output commit failed\n"); frame_done: struct timespec now; @@ -5089,21 +5089,21 @@ static int cmd_in_path(const char *cmd) { return 0; } -static void launch_client(struct tabbed_app *app) { +static void launch_client(struct kick_app *app) { pid_t pid = fork(); if (pid == 0) { /* Own process group so we can kill the whole client tree on exit. */ setpgid(0, 0); const char *xdg_runtime = getenv("XDG_RUNTIME_DIR"); if (!xdg_runtime) xdg_runtime = "/tmp"; - setenv("WAYLAND_DISPLAY", tabbed_socket, 1); + setenv("WAYLAND_DISPLAY", kick_socket, 1); setenv("XDG_RUNTIME_DIR", xdg_runtime, 1); setenv("GDK_BACKEND", "wayland", 1); setenv("QT_QPA_PLATFORM", "wayland", 1); unsetenv("DISPLAY"); /* Unless debugging, don't let client chatter spill onto the launching terminal; the client inherits our stdout/stderr. */ - if (tabbed_log_level() < TABBED_LOG_DEBUG) { + if (kick_log_level() < KICK_LOG_DEBUG) { int nullfd = open("/dev/null", O_WRONLY); if (nullfd >= 0) { dup2(nullfd, STDOUT_FILENO); @@ -5116,7 +5116,7 @@ static void launch_client(struct tabbed_app *app) { } if (pid > 0) { app->pid = pid; - tabbed_log(TABBED_LOG_INFO, "[launch] app=%d pid=%d cmd=%s\n", + kick_log(KICK_LOG_INFO, "[launch] app=%d pid=%d cmd=%s\n", app_index(app), pid, app->cmd); } } @@ -5130,14 +5130,14 @@ static void launch_client(struct tabbed_app *app) { swept away later (see sweep_dead_startup_groups). */ static void launch_all_cli(void) { for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *a = server.apps[i]; + struct kick_app *a = server.apps[i]; if (a->origin != ORIGIN_CLI) continue; launch_client(a); } } /* Drop black tabs whose command's whole process group has exited (e.g. - `tabbed-wlroots /bin/false` -- sh runs false, the group empties, and the + `kick /bin/false` -- sh runs false, the group empties, and the tab would otherwise stay black forever). Runs from the main loop after a SIGCHLD, never from the handler: it frees slots. Group liveness, not the launcher pid's, decides: `sh -c "cmd &"` returns while cmd is still @@ -5145,7 +5145,7 @@ static void launch_all_cli(void) { the tab survives. */ static void sweep_dead_startup_groups(void) { for (int i = 0; i < server.num_apps; i++) { - struct tabbed_app *a = server.apps[i]; + struct kick_app *a = server.apps[i]; if (a->toplevel || !a->pending_claim || a->closing || a->pid <= 0) continue; errno = 0; @@ -5155,7 +5155,7 @@ static void sweep_dead_startup_groups(void) { continue; if (server.active_app == a) { server.active_app = NULL; - struct tabbed_app *succ = pick_successor(a, -1); + struct kick_app *succ = pick_successor(a, -1); if (!succ) succ = pick_successor(a, +1); if (succ) set_active_app(succ); @@ -5167,7 +5167,7 @@ static void sweep_dead_startup_groups(void) { exit(0); } } - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: dropping tab %d (pid %d) " + kick_log(KICK_LOG_INFO, "kick: dropping tab %d (pid %d) " "-- command exited without connecting\n", i, (int)a->pid); remove_app(i); i--; @@ -5175,7 +5175,7 @@ static void sweep_dead_startup_groups(void) { /* If the sweep's succession handed active to a slot that this same pass then removed, put the crown back on some live tab (or nothing). */ if (!server.active_app) { - struct tabbed_app *succ = NULL; + struct kick_app *succ = NULL; for (int i = 0; i < server.num_apps; i++) if (app_live(server.apps[i]) && !server.apps[i]->closing) { succ = server.apps[i]; @@ -5201,7 +5201,7 @@ static void sweep_dead_startup(void) { the new app index, or -1 on allocation failure. */ static int add_tab(const char *cmd) { if (apps_ensure_cap(server.num_apps + 1) != 0) return -1; - struct tabbed_app *app = calloc(1, sizeof(*app)); + struct kick_app *app = calloc(1, sizeof(*app)); if (!app) return -1; app->cmd = strdup(cmd); app->pid = -1; @@ -5235,7 +5235,7 @@ static void sigchld_handler(int sig) { sigchld_seen = 1; int status; pid_t pid; - if (tabbed_log_level() >= TABBED_LOG_DEBUG) { + if (kick_log_level() >= KICK_LOG_DEBUG) { /* snprintf()/write() are async-signal-safe; fprintf() is not (it takes the FILE lock, which can deadlock if we interrupt a logging fprintf in the main loop). */ @@ -5327,23 +5327,23 @@ static bool parse_screen_mode(const char *val) { } int main(int argc, char *argv[]) { - snprintf(tabbed_socket, sizeof(tabbed_socket), "tabbed-wayland-%d", + snprintf(kick_socket, sizeof(kick_socket), "kick-%d", (int)getpid()); const char *runtime = getenv("XDG_RUNTIME_DIR"); if (!runtime) runtime = "/tmp"; - snprintf(socket_path, sizeof(socket_path), "%s/%s", runtime, tabbed_socket); + snprintf(socket_path, sizeof(socket_path), "%s/%s", runtime, kick_socket); /* Clear a stale leftover (e.g. from a crashed previous run with the same name) before we try to bind; harmless if there is none. */ remove_socket_file(); - /* Resolve TABBED_LOG up front so signal handlers can read the cached + /* Resolve KICK_LOG up front so signal handlers can read the cached level without touching non-async-signal-safe functions. */ - tabbed_log_level_init(); + kick_log_level_init(); - /* TABBED_SYNTH_INPUT: keep real host keyboard events out of the test + /* KICK_SYNTH_INPUT: keep real host keyboard events out of the test channel so the stdin feed is the only source of key/modifier input. */ { - const char *v = getenv("TABBED_SYNTH_INPUT"); + const char *v = getenv("KICK_SYNTH_INPUT"); synth_input_only = v && v[0] && v[0] != '0'; } @@ -5362,7 +5362,7 @@ int main(int argc, char *argv[]) { } char **appv = calloc((size_t)argc, sizeof(*appv)); if (!appv) { - fprintf(stderr, "tabbed-wlroots: out of memory\n"); + fprintf(stderr, "kick: out of memory\n"); return 1; } int napps = 0; @@ -5391,7 +5391,7 @@ int main(int argc, char *argv[]) { const char *val = NULL; if (strcmp(argv[i], "--screen-mode") == 0) { if (i + 1 >= argc) { - fprintf(stderr, "tabbed-wlroots: --screen-mode needs a value, " + fprintf(stderr, "kick: --screen-mode needs a value, " "e.g. --screen-mode 1920x1080\n"); free(appv); return 2; @@ -5401,7 +5401,7 @@ int main(int argc, char *argv[]) { val = argv[i] + 14; } else if (strcmp(argv[i], "--modifier") == 0) { if (i + 1 >= argc) { - fprintf(stderr, "tabbed-wlroots: --modifier needs a value, " + fprintf(stderr, "kick: --modifier needs a value, " "e.g. --modifier super\n"); free(appv); return 2; @@ -5412,7 +5412,7 @@ int main(int argc, char *argv[]) { } else if (strcmp(m, "super") == 0) { tab_prefix = PREFIX_SUPER; } else { - fprintf(stderr, "tabbed-wlroots: bad --modifier '%s' " + fprintf(stderr, "kick: bad --modifier '%s' " "(use 'alt' or 'super')\n", m); free(appv); return 2; @@ -5425,7 +5425,7 @@ int main(int argc, char *argv[]) { } else if (strcmp(m, "super") == 0) { tab_prefix = PREFIX_SUPER; } else { - fprintf(stderr, "tabbed-wlroots: bad --modifier '%s' " + fprintf(stderr, "kick: bad --modifier '%s' " "(use 'alt' or 'super')\n", m); free(appv); return 2; @@ -5433,7 +5433,7 @@ int main(int argc, char *argv[]) { continue; } else if (strcmp(argv[i], "--start-cmd-index") == 0) { if (i + 1 >= argc) { - fprintf(stderr, "tabbed-wlroots: --start-cmd-index needs a " + fprintf(stderr, "kick: --start-cmd-index needs a " "value, e.g. --start-cmd-index 2\n"); free(appv); return 2; @@ -5442,7 +5442,7 @@ int main(int argc, char *argv[]) { char *end = NULL; long idx = strtol(n, &end, 10); if (end == n || *end != '\0' || idx < 1 || idx > 2147483647L) { - fprintf(stderr, "tabbed-wlroots: bad --start-cmd-index '%s' " + fprintf(stderr, "kick: bad --start-cmd-index '%s' " "(use a 1-based command number, e.g. --start-cmd-index " "2)\n", n); free(appv); @@ -5457,7 +5457,7 @@ int main(int argc, char *argv[]) { char *end = NULL; long idx = strtol(n, &end, 10); if (end == n || *end != '\0' || idx < 1 || idx > 2147483647L) { - fprintf(stderr, "tabbed-wlroots: bad --start-cmd-index '%s' " + fprintf(stderr, "kick: bad --start-cmd-index '%s' " "(use a 1-based command number)\n", n); free(appv); return 2; @@ -5467,7 +5467,7 @@ int main(int argc, char *argv[]) { } if (val) { if (!parse_screen_mode(val)) { - fprintf(stderr, "tabbed-wlroots: bad --screen-mode '%s' " + fprintf(stderr, "kick: bad --screen-mode '%s' " "(use WxH or WxH@Hz, e.g. 1920x1080 or " "1920x1080@60)\n", val); free(appv); @@ -5485,7 +5485,7 @@ int main(int argc, char *argv[]) { total_apps = 1; } if (start_cmd_index >= 0 && start_cmd_index >= total_apps) { - fprintf(stderr, "tabbed-wlroots: --start-cmd-index %d is out of range: " + fprintf(stderr, "kick: --start-cmd-index %d is out of range: " "1..%d (%d command%s)\n", start_cmd_index + 1, total_apps, total_apps, total_apps == 1 ? "" : "s"); free(appv); @@ -5494,7 +5494,7 @@ int main(int argc, char *argv[]) { for (int i = 0; i < total_apps; i++) { const char *cmd = default_tab ? term_cmd : appv[i]; if (!cmd_in_path(cmd)) { - fprintf(stderr, "tabbed-wlroots: '%s' not found in PATH%s\n", + fprintf(stderr, "kick: '%s' not found in PATH%s\n", cmd, default_tab ? " (set $TERMINAL)" : ""); free(appv); return 1; @@ -5510,13 +5510,13 @@ int main(int argc, char *argv[]) { signal(SIGCHLD, sigchld_handler); signal(SIGUSR1, sigusr1_handler); - /* wlroots logs follow TABBED_LOG: quiet keeps only errors, info drops + /* wlroots logs follow KICK_LOG: quiet keeps only errors, info drops protocol noise, debug shows everything. */ - switch (tabbed_log_level()) { - case TABBED_LOG_DEBUG: + switch (kick_log_level()) { + case KICK_LOG_DEBUG: wlr_log_init(WLR_DEBUG, NULL); break; - case TABBED_LOG_INFO: + case KICK_LOG_INFO: wlr_log_init(WLR_INFO, NULL); break; default: @@ -5524,12 +5524,12 @@ int main(int argc, char *argv[]) { break; } - /* Mode selection: TABBED_MODE=standalone (or any forced WLR_BACKENDS) + /* Mode selection: KICK_MODE=standalone (or any forced WLR_BACKENDS) drives a native output directly (DRM, or headless for tests); the default nested mode blits a headless output into a host window. */ server.standalone = false; { - const char *mode = getenv("TABBED_MODE"); + const char *mode = getenv("KICK_MODE"); const char *wlr_backends = getenv("WLR_BACKENDS"); if (mode && strcmp(mode, "standalone") == 0) server.standalone = true; @@ -5539,7 +5539,7 @@ int main(int argc, char *argv[]) { server.wl_display = wl_display_create(); if (!server.wl_display) { - fprintf(stderr, "tabbed-wlroots: failed to create Wayland display\n"); + fprintf(stderr, "kick: failed to create Wayland display\n"); return 1; } server.loop = wl_display_get_event_loop(server.wl_display); @@ -5579,7 +5579,7 @@ int main(int argc, char *argv[]) { server.backend = wlr_headless_backend_create(server.loop); } if (!server.backend) { - fprintf(stderr, "tabbed-wlroots: failed to create %s backend\n", + fprintf(stderr, "kick: failed to create %s backend\n", server.standalone ? "backend (autocreate)" : "headless backend"); return 1; @@ -5587,7 +5587,7 @@ int main(int argc, char *argv[]) { server.renderer = wlr_renderer_autocreate(server.backend); if (!server.renderer) { - fprintf(stderr, "tabbed-wlroots: no GPU renderer available\n"); + fprintf(stderr, "kick: no GPU renderer available\n"); return 1; } wlr_renderer_init_wl_display(server.renderer, server.wl_display); @@ -5599,7 +5599,7 @@ int main(int argc, char *argv[]) { server.allocator = wlr_allocator_autocreate(server.backend, server.renderer); if (!server.allocator) { - fprintf(stderr, "tabbed-wlroots: failed to create allocator\n"); + fprintf(stderr, "kick: failed to create allocator\n"); return 1; } @@ -5625,7 +5625,7 @@ int main(int argc, char *argv[]) { server.scene = wlr_scene_create(); server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 6); - server.seat = wlr_seat_create(server.wl_display, "tabbed"); + server.seat = wlr_seat_create(server.wl_display, "kick"); wlr_seat_set_capabilities(server.seat, WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD); /* The request_set_selection handler is what actually performs the @@ -5647,7 +5647,7 @@ int main(int argc, char *argv[]) { server.cursor = wlr_cursor_create(); if (!server.output_layout || !server.cursor) { fprintf(stderr, - "tabbed-wlroots: failed to create output layout/cursor\n"); + "kick: failed to create output layout/cursor\n"); return 1; } wlr_cursor_attach_output_layout(server.cursor, server.output_layout); @@ -5683,12 +5683,12 @@ int main(int argc, char *argv[]) { server.xcursor_mgr->scaled_themes.next, mt, link); if (mt->theme && mt->theme->name && strcmp(mt->theme->name, theme) != 0) - tabbed_log(TABBED_LOG_INFO, + kick_log(KICK_LOG_INFO, "[cursor] theme '%s' not found; wlroots builtin cursor " "in use\n", theme); } if (!cur) { - tabbed_log(TABBED_LOG_INFO, + kick_log(KICK_LOG_INFO, "[cursor] no cursor theme available; no pointer shown\n"); } else { wlr_cursor_set_xcursor(server.cursor, server.xcursor_mgr, "default"); @@ -5699,15 +5699,15 @@ int main(int argc, char *argv[]) { /* virtual keyboard fed from the host keyboard */ static const struct wlr_keyboard_impl keyboard_impl = { - .name = "tabbed-keyboard", + .name = "kick-keyboard", }; - wlr_keyboard_init(&server.keyboard, &keyboard_impl, "tabbed-keyboard"); + wlr_keyboard_init(&server.keyboard, &keyboard_impl, "kick-keyboard"); /* fallback keymap until the host sends one */ server.xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (server.xkb_ctx) { xkb_context_set_log_level(server.xkb_ctx, XKB_LOG_LEVEL_DEBUG); - xkb_context_set_log_fn(server.xkb_ctx, tabbed_xkb_log); + xkb_context_set_log_fn(server.xkb_ctx, kick_xkb_log); struct xkb_rule_names names = { .rules = NULL, .model = "pc105", .layout = "us", .variant = NULL, .options = NULL, @@ -5747,29 +5747,29 @@ int main(int argc, char *argv[]) { } if (!wlr_backend_start(server.backend)) { - fprintf(stderr, "tabbed-wlroots: failed to start backend\n"); + fprintf(stderr, "kick: failed to start backend\n"); return 1; } - if (wl_display_add_socket(server.wl_display, tabbed_socket) < 0) { - fprintf(stderr, "tabbed-wlroots: failed to add socket '%s': %s\n", - tabbed_socket, strerror(errno)); + if (wl_display_add_socket(server.wl_display, kick_socket) < 0) { + fprintf(stderr, "kick: failed to add socket '%s': %s\n", + kick_socket, strerror(errno)); return 1; } /* Standalone mode presents onto the native output directly; nested mode connects to the host compositor and presents inside it. */ if (!server.standalone && !host_init()) { - fprintf(stderr, "tabbed-wlroots: could not start nested session\n"); + fprintf(stderr, "kick: could not start nested session\n"); remove_socket_file(); return 1; } - tabbed_log(TABBED_LOG_INFO, "Wayland socket: %s\n", tabbed_socket); + kick_log(KICK_LOG_INFO, "Wayland socket: %s\n", kick_socket); server.apps = calloc((size_t)total_apps, sizeof(*server.apps)); if (!server.apps) { - fprintf(stderr, "tabbed-wlroots: out of memory for %d apps\n", + fprintf(stderr, "kick: out of memory for %d apps\n", total_apps); remove_socket_file(); return 1; @@ -5777,7 +5777,7 @@ int main(int argc, char *argv[]) { server.apps_cap = total_apps; for (int i = 0; i < total_apps; i++) { - struct tabbed_app *app = calloc(1, sizeof(*app)); + struct kick_app *app = calloc(1, sizeof(*app)); if (!app) { remove_socket_file(); return 1; @@ -5795,14 +5795,14 @@ int main(int argc, char *argv[]) { if (server.apps[i]->cmd[0] == '-') { if (i > 0) { fprintf(stderr, - "tabbed-wlroots: warning: %s starts with '-'; it is " + "kick: warning: %s starts with '-'; it is " "run as its own tab, not an option to %s\n" " If intended, quote it: \"%s %s\"\n", server.apps[i]->cmd, server.apps[i - 1]->cmd, server.apps[i - 1]->cmd, server.apps[i]->cmd); } else { fprintf(stderr, - "tabbed-wlroots: warning: %s starts with '-'; if this " + "kick: warning: %s starts with '-'; if this " "is meant for a first command, quote them together, " "e.g. \"%s\"\n", server.apps[i]->cmd, server.apps[i]->cmd); @@ -5823,7 +5823,7 @@ int main(int argc, char *argv[]) { launch_all_cli(); const char *prefix = tab_prefix == PREFIX_SUPER ? "Super" : "Alt"; - tabbed_log(TABBED_LOG_INFO, "tabbed-wlroots: running. " + kick_log(KICK_LOG_INFO, "kick: running. " "%s+Up/Down switches tabs; %s+Shift+Up/Down reorders; " "%s+Delete closes the active tab; " "%s+Shift+T opens a terminal (%s).\n", diff --git a/meson.build b/meson.build index 9975b5b..7660115 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('tabbed-wlroots', 'c', +project('kick', 'c', version: '0.1.0', meson_version: '>=1.0', default_options: ['c_std=c11', 'warning_level=2']) @@ -94,8 +94,8 @@ foreach protocol, p : protocols endif endforeach -executable('tabbed-wlroots', - 'tabbed-wlroots.c', +executable('kick', + 'kick.c', protocol_sources, protocol_headers, dependencies: deps, diff --git a/run.sh b/run.sh index 1e7fdd8..60ca2bb 100755 --- a/run.sh +++ b/run.sh @@ -3,4 +3,4 @@ set -e cd "$(dirname "$0")" -exec ./build/tabbed-wlroots "$@" +exec ./build/kick "$@" diff --git a/scripts/nested-labwc.sh b/scripts/nested-labwc.sh index 186f306..3652d6a 100755 --- a/scripts/nested-labwc.sh +++ b/scripts/nested-labwc.sh @@ -2,10 +2,10 @@ # Throwaway dev wrapper: run a command inside a nested labwc (wlroots-family # host) so the clipboard bridge uses the wlr-data-control backend. # Usage: nested-labwc.sh [--x11] -# Default command: tabbed-wlroots with two wltest tabs. +# Default command: kick with two wltest tabs. set -e -REPO="${TABBED_REPO:-/home/ahamilton/code/tabbed-wayland}" +REPO="${KICK_REPO:-/home/ahamilton/code/tabbed-wayland}" RUNTIME="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}" export WLR_WL_OUTPUTS="${WLR_WL_OUTPUTS:-1}" @@ -61,7 +61,7 @@ echo "[nested-labwc] nested labwc socket: $SOCK" export WAYLAND_DISPLAY="$SOCK" if [ "$#" -eq 0 ]; then - set -- "$REPO/build/tabbed-wlroots" \ + set -- "$REPO/build/kick" \ "$REPO/build/wltest '#ff0000'" \ "$REPO/build/wltest '#0000ff'" fi diff --git a/scripts/stress-clipboard.sh b/scripts/stress-clipboard.sh index 4b79358..dd90f28 100755 --- a/scripts/stress-clipboard.sh +++ b/scripts/stress-clipboard.sh @@ -8,7 +8,7 @@ # clipboard failures are the motivation). set -u -REPO="${TABBED_REPO:-$(cd "$(dirname "$0")/.." && pwd)}" +REPO="${KICK_REPO:-$(cd "$(dirname "$0")/.." && pwd)}" ITER="${1:-30}" shift 2>/dev/null || shift diff --git a/test-headless.sh b/test-headless.sh index 73d28c8..fecb486 100755 --- a/test-headless.sh +++ b/test-headless.sh @@ -5,7 +5,7 @@ # The nested tests open the compositor's single host window on the ambient # Wayland session. This wrapper re-hosts that window inside an invisible # headless compositor: a second, standalone instance of the same binary -# (TABBED_MODE=standalone WLR_BACKENDS=headless) whose output is shown +# (KICK_MODE=standalone WLR_BACKENDS=headless) whose output is shown # nowhere. WAYLAND_DISPLAY is pointed at that headless host for the pytest # run, so every nested session maps its window inside the headless scene # instead of flashing on the real desktop. @@ -19,9 +19,9 @@ set -e cd "$(dirname "$0")" -BIN=build/tabbed-wlroots +BIN=build/kick WL=build/wltest -HOST_LOG=/tmp/tabbed-headless-host.log +HOST_LOG=/tmp/kick-headless-host.log for p in "$BIN" "$WL"; do if [ ! -x "$p" ]; then @@ -37,7 +37,7 @@ rm -f "$HOST_LOG" host_tab="$WL '#112233'" # A real font, mirroring _pick_font() in tests/test_smoke.py. -font="${TABBED_FONT:-}" +font="${KICK_FONT:-}" if [ -z "$font" ]; then for f in \ /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf \ @@ -63,10 +63,10 @@ fi XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp}" \ XDG_DATA_HOME="${XDG_DATA_HOME:-}" \ XDG_DATA_DIRS="${XDG_DATA_DIRS:-}" \ - TABBED_LOG=2 \ - TABBED_MODE=standalone \ + KICK_LOG=2 \ + KICK_MODE=standalone \ WLR_BACKENDS=headless \ - TABBED_FONT="$font" \ + KICK_FONT="$font" \ XCURSOR_THEME=Adwaita unset WAYLAND_DISPLAY exec stdbuf -oL "$BIN" "$host_tab" @@ -87,7 +87,7 @@ while [ -z "$socket" ]; do cat "$HOST_LOG" >&2 exit 1 fi - socket=$(sed -n 's/.*Wayland socket: \(tabbed-wayland-[0-9][0-9]*\).*/\1/p' \ + socket=$(sed -n 's/.*Wayland socket: \(kick-[0-9][0-9]*\).*/\1/p' \ "$HOST_LOG" | tail -n 1) if [ -z "$socket" ] && [ "$(date +%s)" -ge "$deadline" ]; then echo "test-headless.sh: timed out waiting for the headless host socket:" >&2 diff --git a/tests/test_smoke.py b/tests/test_smoke.py index 0308f07..723c626 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Smoke tests for tabbed-wlroots. +"""Smoke tests for kick. The compositor is launched as a nested display (child of the host Wayland session) and driven over the stdin event feed: raw keyboard @@ -28,7 +28,7 @@ import time import pytest ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -BIN = os.path.join(ROOT, "build", "tabbed-wlroots") +BIN = os.path.join(ROOT, "build", "kick") WL = os.path.join(ROOT, "build", "wltest") LOG = "/tmp/tabtest.log" RED = "#ff0000" @@ -36,7 +36,7 @@ BLUE = "#0000ff" GREEN = "#00ff00" # Raw keycodes used by the compositor's own key handler (see -# host_kbd_key in tabbed-wlroots.c). Names, not numbers, in tests. +# host_kbd_key in kick.c). Names, not numbers, in tests. F = 33 F11 = 87 UP = 103 @@ -61,10 +61,10 @@ CTL_CMD_PTR_MOTION = 4 ACTIVE_RE = re.compile(r"active app=(\d+)") CLAIM_RE = re.compile(r"\[claim\] app=(\d+) pid=(\d+)") -SOCKET_RE = re.compile(r"Wayland socket: (tabbed-wayland-\d+)") +SOCKET_RE = re.compile(r"Wayland socket: (kick-\d+)") -# Font paths the compositor searches (overlay_pick_font in tabbed-wlroots.c); +# Font paths the compositor searches (overlay_pick_font in kick.c); # used to make the standalone headless session build a real glyph atlas. FONT_PATHS = [ "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", @@ -78,8 +78,8 @@ FONT_PATHS = [ def _pick_font(): - """First existing font path, from $TABBED_FONT or the default list.""" - env_font = os.environ.get("TABBED_FONT") + """First existing font path, from $KICK_FONT or the default list.""" + env_font = os.environ.get("KICK_FONT") if env_font and os.path.isfile(env_font): return env_font for path in FONT_PATHS: @@ -108,7 +108,7 @@ def _preexec_death(expected_ppid): class Session: - """A running tabbed-wlroots instance plus helpers.""" + """A running kick instance plus helpers.""" def __init__(self, proc): self.proc = proc @@ -123,7 +123,7 @@ class Session: def wait_for(self, pattern, timeout=15.0): """Wait until `pattern` matches somewhere in the whole log. - Re-scans from the start each poll: tabbed's log lines can arrive + Re-scans from the start each poll: kick's log lines can arrive out of order (e.g. `map app=1` before `map app=0`), so a line may enter the file before we happen to be looking for it. """ @@ -432,7 +432,7 @@ def session(): pass proc = subprocess.Popen( - ["env", "TABBED_LOG=2", "TABBED_SYNTH_INPUT=1", "stdbuf", "-oL", + ["env", "KICK_LOG=2", "KICK_SYNTH_INPUT=1", "stdbuf", "-oL", BIN, f"{WL} '{RED}'", f"{WL} '{BLUE}'"], stdin=subprocess.PIPE, stdout=open(LOG, "ab"), stderr=subprocess.STDOUT, @@ -467,8 +467,8 @@ def standalone_session(): # open a second nested window). WLR_BACKENDS=headless forces the # headless backend and the standalone output path. env = dict(os.environ) - env["TABBED_LOG"] = "2" - env["TABBED_MODE"] = "standalone" + env["KICK_LOG"] = "2" + env["KICK_MODE"] = "standalone" env["WLR_BACKENDS"] = "headless" env.pop("WAYLAND_DISPLAY", None) proc = subprocess.Popen( @@ -478,10 +478,10 @@ def standalone_session(): "XDG_RUNTIME_DIR=" + env.get("XDG_RUNTIME_DIR", "/tmp"), "XDG_DATA_HOME=" + env.get("XDG_DATA_HOME", ""), "XDG_DATA_DIRS=" + env.get("XDG_DATA_DIRS", ""), - "TABBED_LOG=2", - "TABBED_MODE=standalone", + "KICK_LOG=2", + "KICK_MODE=standalone", "WLR_BACKENDS=headless", - "TABBED_FONT=" + (env.get("TABBED_FONT") or _pick_font() or ""), + "KICK_FONT=" + (env.get("KICK_FONT") or _pick_font() or ""), "XCURSOR_THEME=Adwaita", "stdbuf", "-oL", BIN, f"{WL} '{RED}'", f"{WL} '{BLUE}'"], @@ -788,8 +788,8 @@ def _spawn_standalone(extra_env, *apps): except FileNotFoundError: pass env = dict(os.environ) - env["TABBED_LOG"] = "2" - env["TABBED_MODE"] = "standalone" + env["KICK_LOG"] = "2" + env["KICK_MODE"] = "standalone" env["WLR_BACKENDS"] = "headless" env.pop("WAYLAND_DISPLAY", None) env.pop("XCURSOR_THEME", None) @@ -801,10 +801,10 @@ def _spawn_standalone(extra_env, *apps): "XDG_RUNTIME_DIR=" + env.get("XDG_RUNTIME_DIR", "/tmp"), "XDG_DATA_HOME=" + env.get("XDG_DATA_HOME", ""), "XDG_DATA_DIRS=" + env.get("XDG_DATA_DIRS", ""), - "TABBED_LOG=2", - "TABBED_MODE=standalone", + "KICK_LOG=2", + "KICK_MODE=standalone", "WLR_BACKENDS=headless", - "TABBED_FONT=" + (env.get("TABBED_FONT") or _pick_font() or "")] + "KICK_FONT=" + (env.get("KICK_FONT") or _pick_font() or "")] for key in ("XCURSOR_PATH", "XCURSOR_THEME"): if env.get(key): cmd.append("%s=%s" % (key, env[key])) @@ -922,7 +922,7 @@ def test_standalone_headless_screen_mode_bad_value_exits(tmp_path): "PATH=" + env["PATH"], "HOME=" + env.get("HOME", "/"), "XDG_RUNTIME_DIR=" + env.get("XDG_RUNTIME_DIR", "/tmp"), - "TABBED_MODE=standalone", + "KICK_MODE=standalone", "WLR_BACKENDS=headless", "stdbuf", "-oL", BIN] + case, @@ -1011,7 +1011,7 @@ NEED_WL_CLIPBOARD = shutil.which("wl-copy") is None or shutil.which("wl-paste") @pytest.mark.skipif(NEED_WL_CLIPBOARD, reason="wl-clipboard tools not installed") def test_clipboard_nested_to_host(session): - token = f"tabbed-n2h-{os.getpid()}-{time.monotonic_ns()}" + token = f"kick-n2h-{os.getpid()}-{time.monotonic_ns()}" copy = subprocess.Popen( ["wl-copy", "-f", token], env={**os.environ, "WAYLAND_DISPLAY": session.socket}, @@ -1027,7 +1027,7 @@ def test_clipboard_nested_to_host(session): @pytest.mark.skipif(NEED_WL_CLIPBOARD, reason="wl-clipboard tools not installed") def test_clipboard_host_to_nested(session): - token = f"tabbed-h2n-{os.getpid()}-{time.monotonic_ns()}" + token = f"kick-h2n-{os.getpid()}-{time.monotonic_ns()}" copy = subprocess.Popen( ["wl-copy", "-f", token], env=dict(os.environ), @@ -1314,7 +1314,7 @@ def _nested_session(*tabs, extra_args=()): except FileNotFoundError: pass proc = subprocess.Popen( - ["env", "TABBED_LOG=2", "TABBED_SYNTH_INPUT=1", "stdbuf", "-oL", + ["env", "KICK_LOG=2", "KICK_SYNTH_INPUT=1", "stdbuf", "-oL", BIN, *extra_args] + list(tabs), stdin=subprocess.PIPE, stdout=open(LOG, "ab"), stderr=subprocess.STDOUT, @@ -1433,7 +1433,7 @@ def test_alt_delete_activates_right_neighbor(): assert s.wait_active_change(1) == 2, \ "Alt+Delete did not activate the right neighbor" assert s.proc.poll() is None, "compositor exited after Alt+Delete" - s.wait_for(r"tabbed-wlroots: closing tab 1") + s.wait_for(r"kick: closing tab 1") finally: s.close() if s.proc.poll() is None: @@ -1589,7 +1589,7 @@ def test_modifier_super_flag(): # pre-close value even though the tab underneath changed. count = s.active_count() s.chord(SUPER, DELETE) - s.wait_for(r"tabbed-wlroots: closing tab") + s.wait_for(r"kick: closing tab") deadline = time.monotonic() + 5.0 while s.active_count() <= count: assert s.proc.poll() is None, \ @@ -1728,7 +1728,7 @@ def test_no_args_opens_terminal(): # The one tab is the terminal named by TERMINAL (a wltest, so no real # terminal emulator has to be installed on the test host). proc = subprocess.Popen( - ["env", "TABBED_LOG=2", "TABBED_SYNTH_INPUT=1", + ["env", "KICK_LOG=2", "KICK_SYNTH_INPUT=1", f"TERMINAL={WL} '{RED}'", "stdbuf", "-oL", BIN], stdin=subprocess.PIPE, stdout=open(LOG, "ab"), stderr=subprocess.STDOUT, @@ -1773,7 +1773,7 @@ def test_close_black_tab_active_last(): try: s.wait_for(r"\[diag\] map app=0") s.chord(ALT, DELETE) - s.wait_for(r"tabbed-wlroots: closing tab 1") + s.wait_for(r"kick: closing tab 1") # The black tab is gone; the RED survivor becomes active in its place. s.wait_for(r"active app=0") assert s.proc.poll() is None, \ @@ -1841,7 +1841,7 @@ def test_start_cmd_index_errors(): "PATH=" + env["PATH"], "HOME=" + env.get("HOME", "/"), "XDG_RUNTIME_DIR=" + env.get("XDG_RUNTIME_DIR", "/tmp"), - "TABBED_MODE=standalone", + "KICK_MODE=standalone", "WLR_BACKENDS=headless", "stdbuf", "-oL", BIN] + case,