Skip to content

Instantly share code, notes, and snippets.

@delthas
Last active August 1, 2024 09:45
Show Gist options
  • Save delthas/d451e2cc1573bb2364839849c7117239 to your computer and use it in GitHub Desktop.
Save delthas/d451e2cc1573bb2364839849c7117239 to your computer and use it in GitHub Desktop.

Custom App ID in terminal emulators

TL;DR This simple spec enables terminal apps to have their own icons, window grouping, and app pinning, by letting terminal emulators know about the ID of the app they are running.

Rationale

There are two general ways of starting a terminal application:

  • "Manually", from a shell, in a terminal emulator window, typing the application name, pressing Enter
  • From an app launcher, typing the application name, starting it

The manual way starts the app in the window. This approach is best for starting and stopping multiple terminal apps in the same session, opening multiple tabs in the terminal, ...

The launcher way creates a new window for the app. This approach is best suited for large CLI apps that will stay open for a while: CLI IM clients, CLI email readers, ...

When a long-running app is the only process in a terminal window, the window effectively "becomes" the app, from the POV of a user. As such, a user could expect the following when starting a terminal app:

  • The terminal window features the icon of the app
  • Notifications started by the terminal have the icon of the app
  • If supported by the compositor, the app can be "pinned" to the dock. When the app is clicked later on the dock, the app is started again.
  • If supported by the compositor, windows of this app can be grouped together, but are not grouped with the other terminal windows not running this app.

This behavior is typically determined by the App ID (Wayland) or the Window Class (X) of the terminal window. If there is a myapp.desktop file for the app, and the terminal window sets the myapp app ID, then the compositor will consider the window to represent the app, and set the appropriate icon, ...

Until now, there was no easy way to get this behavior:

  • Terminal applications created with Terminal=true are started without specific options, so terminal emulators start with their own app ID, not that of the app
  • As a workaround, a custom .desktop application file could be created, to explicitly specify a terminal emulator and an app ID, but this was terminal-dependent

The goal of this specification is to enable apps to tell terminal emulators about their name/ID, so that terminal emulators can set their window app ID and tell the compositor that they contain this app.

Quick example

Here's a simple command to try out the feature. This changes the terminal emulator window icon to that of VLC.

printf '\e]176;vlc\e\\\n'

Supporting apps

Terminal emulators

  • foot >= 1.17.0 (2024/04/02)

Terminal libraries

  • vaxis >= 0.9.0 (2024/06/17)

Terminal apps

The escape sequence

Getting the App ID

The current App ID of the terminal emulator window can be queried with:

OSC 176 ; ? ST

The terminal then replies with:

OSC 176 ; appID ST

Setting the App ID

The App ID of the terminal emulator window can be set/reset with:

OSC 176 ; appID ST

Details

OSC (operating system command) is typically ESC ].

appID is an optional string describing the desired App ID / Window Class of the running app. If empty when setting, the app unsets its app ID.

The sequence is terminated with ST (string terminator) which is typically ESC \. (Although ST is the standard sequence according to ECMA-48 §8.3.89, often the BEL (\a) character is used instead. This nonstandard choice originates from XTerm, and was later adopted by probably all terminal emulators to terminate OSC sequences. Nevertheless, we encourage the use of the standard ST.)

(For OSC and ST, their C0 variant was shown above. They have another, C1 form which might be supported in some contexts. In 8-bit Latin-X character sets they are the single bytes 0x9d and 0x9c, respectively. In UTF-8 mode some terminal emulators deliberately do not implement C1 support because these bytes would conflict with the UTF-8 encoding, while some other terminal emulators recognize the UTF-8 representation of U+009d (i.e. 0xc2 0x9d) and U+009c (i.e. 0xc2 0x9c), respectively. Since C1 is not universally supported in today's default UTF-8 encoding, its use is discouraged.)

Terminal implementation notes

A terminal emulator should probably only set this custom App ID when the application requesting it is the only one running in the window. In other words, the App ID should be ignored when multiple tabs are open in the terminal window.

The request by the application to set the App ID is best-effort, so the terminal window should likely not show error messages to the user in case it is not possible to set it.

A terminal emulator could implement some rate limiting on app ID changes.

In its simplest form, a patch for a Wayland terminal emulator could be:

// ... When OSC 176 is received
if (!strcmp(osc_param, "?")) {
  // Querying
  // Send current app ID to the app
} else {
  // Setting
  xdg_toplevel_set_app_id(toplevel, osc_param);
}

Application implementation notes

In most cases, applications should get the current app ID on start, save it, then set their app ID, and on exit reset the app ID back to its previous value.

Detecting availability of the feature

In order to detect terminal support for the feature, an app can make an OSC 176 query and check its reply.

Backward compatibility

Any terminal that correctly implements OSC parsing according to ECMA-48 is guaranteed not to suffer from compatibility issues. That is, even if setting the App ID isn't supported, the request is silently ignored, without artifacts.

If a terminal emits garbage upon an OSC App ID sequence, that terminal is buggy according to ECMA-48. It is, and will always be, outside of the scope of this specification to deal with buggy terminals.

Length limits

Desktop application names are limited to 255 characters, so it is expected that App IDs stay below this length.

@dnkl
Copy link

dnkl commented Feb 6, 2024

OSC queries normally has the number first; the ? is the argument. Replies are normally on the same format the application would use to set the OSC. So:

OSC 176 ; ? ST to query, and then the reply would be OSC 176 ; title ST.

I just added support for this to foot.

@craigbarnes
Copy link

A terminal emulator should probably only set this custom App ID when the application requesting it is the only one running in the window. In other words, the App ID should be ignored when multiple tabs are open in the terminal window.

What about when a TUI app sets the app ID (while running in a single tab window) and then the user subsequently opens another tab? Is the terminal expected to switch it back to a neutral value at that point and ignore further requests until there's only 1 tab remaining? That seems somehow rather inconsistent to me, even though in foot's case it's not an issue.

@craigbarnes
Copy link

craigbarnes commented Feb 12, 2024

Is the terminal expected to switch it back to a neutral value at that point and ignore further requests until there's only 1 tab remaining?

If the answer to this question is "yes", what happens when the 1 remaining tab is running an app that previously set a custom ID? Should that ID be restored?

@delthas
Copy link
Author

delthas commented Aug 1, 2024

@craigbarnes I'd say it'd be implementation-dependent, but I'd typicaly expect each tab to store its "requested" app ID, and a terminal with multiple tabs could do the following:

  • If there is only one tab; use that tab app ID
  • If there are multiple tabs with the same app ID: use that app ID
  • If there are multiple tabs with different app IDs: use the terminal built-in app ID (ignore the tabs app IDs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment