Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 41 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,36 +61,52 @@ lives in **VsCodeOsCore** — a VS Code extension that ships *inside* the editor
rather than being installed from the Marketplace. Its source is in
[`extension/`](extension/), and it adds:

- **An all-apps button**, in the bottom-left corner — a searchable grid of every
program on the machine, the way a start menu works.
- **A tray**, at the right end of the status bar. Left to right: now playing,
battery, volume, network, the clock and date, and the power button in the
corner. Each one opens a flyout in the bottom panel — a Windows-style card
that rises directly above the item you clicked.
battery, volume, network, Bluetooth, the clock and date, and the power button
in the corner. Each one opens a card in the side bar. (VS Code has no API for
a popup anchored to a status bar item; the side bar is the closest thing that
does not take the terminal panel away from you. `vscodeos.flyout.location`
puts the cards back in the bottom panel if you prefer them there.)
- **Power** — sleep, restart, shut down and log out, with a confirmation.
- **Calendar** — a month grid with today highlighted, on the clock.
- **Quick settings** — Wi-Fi, Bluetooth, airplane mode, energy saver, night
light and accessibility, plus brightness and volume sliders. Tiles hide
themselves when the hardware is not there, rather than showing a dead switch.
- **Network** — scan, connect with a password, and switch between saved
connections.
- **Power settings**, on the battery — energy saver, a brightness slider whose
moon button toggles night light, and the charge left. Nothing else: the radio
switches live on the cards that own them.
- **Network** — scan, connect with a password, switch between saved connections,
and airplane mode.
- **Bluetooth** — turn the adapter on, scan for devices, pair, connect and
forget. The button hides itself when there is no adapter.
- **Task Manager**, in the activity bar — processes with CPU and memory, per-core
meters, load average, uptime and CPU temperature, sortable and filterable, with
End task.
- **Files** — a graphical file explorer with a places sidebar, grid and list
views, rename, trash, copy and paste. Text opens in the editor; everything else
goes to `xdg-open`.
views, rename, trash, copy and paste. **Everything opens in the editor**: text
in the text editor, images in the built-in preview, video and audio in the
media player.
- **Browser** — a real browser rendered *inside* an editor tab, with tabs, an
address bar and history. It drives a headless Chromium and streams its picture
back, which is the only way to show sites that refuse to be framed. "Open in
browser" hands the page to a real window when that is the better answer.
- **Media Player** — video and audio in a tab, with a playlist of whatever else
is in the folder.
- **Music** — transport controls for whatever is playing, over MPRIS, plus
one-click launchers that open Spotify Web and YouTube Music as their own
browser windows.
- **Apps** — Calculator, Notepad, Paint, Screenshot and Voice Recorder. `VS Code
OS: All Apps…` in the command palette (**Ctrl** + **Shift** + **P**) lists
everything.
one-click launchers for Spotify Web and YouTube Music.
- **Updater** — a GUI for the two update paths below, with live output and a
restart prompt when one is needed.
- **Apps** — Calculator, Paint, Screenshot and Voice Recorder. Pressing
**Print Screen** jumps straight to a region capture.

There is deliberately no Notepad: the editor is a better one, and the file
manager now opens text in it.

Two honest limits, both imposed by VS Code rather than by this project:
**Spotify audio cannot play inside the editor** (VS Code's Electron ships no
Widevine, so the Web Playback SDK cannot work — which is exactly why the player
controls a real browser window instead), and **Microsoft Edge is not on either
image** (it is AUR-only on Arch, and Microsoft publishes no ARM64 Linux build at
all, so the Pi could never have matched). The browser launcher prefers
all, so the Pi could never have matched). Everything browser-shaped prefers
`microsoft-edge-stable` if you install it yourself, and falls back to Chromium.

Every part of the shell can be turned off individually in settings under
Expand Down Expand Up @@ -205,13 +221,22 @@ VSCODEOS_RESPAWN=1 # 0 = do not relaunch when VS Code exits

## Day-to-day

The **Updater** app does all of this with buttons — open it from the all-apps
button in the bottom-left corner. By hand:

```bash
sudo pacman -Syu # update the Arch base
sudo vscodeos-update-code # update VS Code itself (it is not a pacman package)
nmtui # join a Wi-Fi network (or use the tray)
code ~/Projects/thing # open something in the running editor
```

The Updater runs the same work through `/usr/local/bin/vscodeos-update`, which
it launches with `pkexec`. polkit is configured to allow that one program
without a password (`/etc/polkit-1/rules.d/49-vscodeos.rules`) because there is
no authentication agent in a session whose entire UI is the editor — a password
prompt would have nowhere to appear.

Extensions, settings sync and Marketplace sign-in all work normally;
`gnome-keyring` is started by the session so credentials persist.

Expand Down
5 changes: 5 additions & 0 deletions archiso/packages.x86_64
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ mkinitcpio-nfs-utils
sudo
polkit
dbus
# checkupdates, for the Updater app. It lists pending updates against a copy of
# the sync database, so the GUI never has to run `pacman -Sy` - which would
# leave the real database half-synced and the machine one command away from a
# partial upgrade.
pacman-contrib

# Live medium / installer tooling
arch-install-scripts
Expand Down
5 changes: 5 additions & 0 deletions archiso/profiledef.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ file_permissions=(
["/usr/local/bin/vscodeos-kiosk"]="0:0:755"
["/usr/local/bin/vscodeos-update-code"]="0:0:755"
["/usr/local/bin/vscodeos-install-extensions"]="0:0:755"
# This one is load-bearing for security, not just for tidiness: polkit grants
# `pkexec /usr/local/bin/vscodeos-update` without a password, so a copy the
# kiosk user could write to would be a one-line path to root.
["/usr/local/bin/vscodeos-update"]="0:0:755"
["/usr/local/bin/vscodeos-screenshot"]="0:0:755"
["/usr/local/bin/code"]="0:0:755"
["/etc/sudoers.d/vscodeos"]="0:0:0440"
)
45 changes: 37 additions & 8 deletions extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,44 @@ accidentally uninstalled.

| | |
| --- | --- |
| **Tray** | Power button, clock and date, battery, volume, network and now-playing, at the right end of the status bar |
| **Flyouts** | Power, calendar, quick settings, volume mixer, network picker and music player |
| **Launcher** | An all-apps button in the bottom-left corner: a searchable grid of every program |
| **Tray** | Now-playing, battery, volume, network, Bluetooth, clock and date, and the power button, at the right end of the status bar |
| **Flyouts** | Apps, power, calendar, power settings, volume mixer, network picker, Bluetooth and music player |
| **Task Manager** | Processes with CPU/RAM, per-core meters, load, uptime and thermals, in the activity bar |
| **Files** | A graphical file explorer: places sidebar, grid/list, rename, trash, copy/paste, open with `xdg-open` |
| **Files** | A graphical file explorer: places sidebar, grid/list, rename, trash, copy/paste. Everything opens in the editor |
| **Browser** | A headless Chromium streamed into an editor tab, with tabs, an address bar and history |
| **Media Player** | Video and audio in a tab, with a folder playlist |
| **Music** | MPRIS transport for whatever is playing, plus launchers for Spotify Web and YouTube Music |
| **Browser** | Launches Edge → Chromium → Firefox, whichever is installed |
| **Apps** | Calculator, Notepad, Paint, Screenshot and Voice Recorder |
| **Updater** | pacman, VS Code and the shell itself, with live output |
| **Apps** | Calculator, Paint, Screenshot and Voice Recorder |

Every feature is behind a `vscodeos.<feature>.enabled` setting, all defaulting to
on. `VS Code OS: All Apps…` in the command palette lists everything.
on. The all-apps button, or `VS Code OS: All Apps…` in the command palette,
lists everything.

### Three things worth knowing

**The flyouts are not popups.** VS Code has no API to anchor one to a status bar
item, and the only floating-window route — moving an editor to an auxiliary
window — brings editor tab chrome with it and cannot be sized or placed. So they
are a webview view, in the side bar by default. The bottom panel, where they used
to live, is where the terminal is; `vscodeos.flyout.location` puts them back.

**The browser is a screencast.** Every site worth visiting sends
`X-Frame-Options`, which is why VS Code's own Simple Browser shows a blank
rectangle on most of them. `puppeteer-core` drives a headless Chromium, CDP's
`Page.startScreencast` pushes JPEG frames into an `<img>`, and pointer and key
events go back through `Input.dispatch*`. That costs an encode and a decode per
frame, so `vscodeos.browser.frameRate` and `vscodeos.browser.quality` are
settings — turn them down on a Pi — the stream stops when the tab is hidden, and
"Open in browser" is always there. `puppeteer-core` is the extension's one
runtime dependency and is bundled into `dist/extension.js` like everything else.

**Print Screen is bound by the window manager, not here.** On X11 the Print key
never reaches Electron as a keydown, so a contributed keybinding cannot see it.
Openbox runs `/usr/local/bin/vscodeos-screenshot`, which hands
`vscode://vscodeos.vscodeos-core/screenshot?mode=region` to the running editor,
where a `registerUriHandler` picks it up.

## Developing

Expand Down Expand Up @@ -57,8 +85,9 @@ src/
extension.ts activate(): wires everything, one DisposableStore
sys/ the only code that touches the machine
statusbar/ the tray, and the priority ladder that orders it
views/ flyout (panel) and task manager (activity bar) providers
apps/ file explorer, mini-apps, panel plumbing
views/ flyout (side bar) and task manager (activity bar) providers
apps/ registry, file explorer, browser, media player, updater,
mini-apps, panel plumbing
webview/ HTML shell + the host↔webview message types
media/
src/ one TypeScript entry point per page, shared code in src/lib
Expand Down
16 changes: 13 additions & 3 deletions extension/esbuild.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
// media/src/*.ts -> media/dist/*.js browser/IIFE, runs inside each webview
//
// Nothing is left in node_modules: the shipped extension is package.json, dist/
// and media/, which keeps the payload that goes into every image small.
// and media/, which keeps the payload that goes into every image small. That
// applies to puppeteer-core too - the browser app's only runtime dependency is
// bundled into dist/extension.js like everything else.

import * as esbuild from 'esbuild';
import { readdirSync } from 'node:fs';
Expand Down Expand Up @@ -40,8 +42,16 @@ const configs = [
platform: 'node',
target: 'node18',
format: 'cjs',
// Supplied by the extension host at run time, never bundled.
external: ['vscode'],
external: [
// Supplied by the extension host at run time, never bundled.
'vscode',
// Optional native accelerators that `ws` (a puppeteer-core dependency)
// requires inside a try/catch. esbuild resolves them at build time
// regardless of the guard, so they have to be named here or the
// bundle fails on a machine that never installed them.
'bufferutil',
'utf-8-validate',
],
},
{
...common,
Expand Down
Loading