Skip to content

App Usage

P3DROVFX edited this page Oct 12, 2026 · 1 revision

App Usage and Screen Time

The App Usage app answers "where did my day — and my battery — go?": per-app screen time, CPU and GPU time, memory, launches, energy and the battery's own history, by hour, day, week or month; and it holds the daily limits and focus schedules that can block an app when your time is up. It is the sibling of the Clock App (same window frame and widgets), opened with Super + U.

Everything is measured locally by a tiny native sampler — nothing is sent anywhere — and it is off until you turn it on.

Quick start

  1. Settings → App Usage → turn collection on (appStats.enable).
  2. If the sampler has not been built yet, the app opens on Usage stats aren't installed yet with the commands to run (below). It collects as soon as the binary exists — no shell restart.
  3. Super + U opens the app (toggle). Tabs: Apps · Battery · Limits. The first day file appears one flush interval (60 s) after the sampler starts, so a blank first minute is normal.
qs -c ii ipc call usage toggle     # open/close
qs -c ii ipc call usage limits     # open on the Limits tab

Apps

A ranked list of apps for the period you pick (Day / Week / Month, with arrows and a calendar-style picker), ranked by a metric you choose: Screen time (focused), Foreground, Background, CPU, GPU, Memory, Launches or Energy. A header shows the headline figure with a vs. previous period change (optional — it doubles the files a month view has to read), a column chart for the period, and an activity heatmap. Selecting an app narrows everything to it (Only ), and a button on the app sets a daily limit.

  • Device screen time is counted once however many windows were on screen; Unattributed is the energy that belongs to no app (idle draw, kernel threads, backlight, radios) — shown next to the apps, not smeared over them.
  • Background services (processes with no window) are always recorded, and Count background services decides whether they appear in the list and totals.
  • Energy is measured from RAPL counters when available (Intel, with the udev rule below), otherwise estimated from battery drain — so it reads zero while plugged in.

Battery

The pack alongside the apps: charge level over time, hour by hour and day by day discharged, average draw, the lowest level, time to full or empty, charging periods ("held at 80 %" when a charge limit applies), health and cycle count, and where the energy went by app. It needs a battery; a desktop shows "this machine runs on mains power". Only if the sampler was built with battery support; otherwise it tells you to rebuild.

Limits

Two kinds of rule, both counting focused time only (not idle time, not a locked screen, not a window hidden under the block):

  • Daily limits — for one app (matched by window classes) or for all screen time, in minutes per day, on chosen days (Every day / Weekdays / Weekends or custom). The total limit counts every focused minute except Always allowed apps.
  • Focus schedules — block chosen apps (or all apps) between two times of day on chosen days.

Each rule can be strict (extra time needs the PIN). Tiles show state by colour — primary while fine, tertiary in the warning window, error once used up — with a hero ring for the total limit, a week chart per limit, and "Most used today" suggestions to start from.

When time is up a full-screen overlay (screenTimeOverlay, Overlay layer, exclusive keyboard, a scrim that swallows clicks) covers the app: Close the app, Lock the screen (for the total limit and all-apps schedules), or +1 min / +15 min / the rest of the day (asking for the PIN when strict). With Close the app on its own after set, a draining ring counts down and closing is kill -TERM of that window's processes (paused while you type the PIN). Warnings come before: Warn before time is up (default 5 min), a last-minute warning, Notify when time is up, and Remind me while over a limit every 15 minutes if you chose to ignore it.

PIN. Optional, 4+ digits, stored as a salted hash — a speed bump, not a vault (anyone with file access can edit the config). With PIN protects changes, editing, removing or pausing a limit asks for it and then allows edits for ten minutes.

A day's bookkeeping (ignored limits, extra time granted, warnings already sent, counters) is one JSON in Persistent.states.screenTime.dayJson, reset when the date changes. It complements the Bedtime tab of the Clock App: Bedtime is about when you stop, limits about how much.


Settings

The gear in the app's top bar (and Settings → App Usage) holds: sampling interval (10 s default — shorter is finer window attribution at more CPU), flush interval, Days kept with the retention mode (Keep the previous month — the window slides between 31 and 62 days so this month can always be compared with last — or a Fixed number of days), Energy source (Automatic / RAPL / Battery drain / None), Pause after idle for (5 min; 0 keeps foreground time running), Hide apps under…, which tab and metric the app opens on, and Delete history. The sampler reads these once at start, so changing them restarts it. Quick actions: Open folder (the day files) and a flush button.

Installing the sampler

The QML ships with the shell; the sampler is a small Rust daemon (scripts/appStats/app_stats, ~530 KB binary, ~3.5 MB of memory while running) that is built on your machine because it is not tracked in git.

# 1. Build it. Rust is the only requirement (`ii-p3drovfx deps add rust-helpers` installs cargo); the first build fetches two crates (needs network).
~/.config/quickshell/ii/scripts/rust-helpers.sh build app_stats

# 2. Optional, Intel only: let your user read the RAPL energy counters.
sudo tee /etc/udev/rules.d/99-rapl-readable.rules >/dev/null <<'EOF'
SUBSYSTEM=="powercap", KERNEL=="intel-rapl:*", TEST=="/sys$devpath/energy_uj", \
  RUN+="/usr/bin/chgrp wheel /sys$devpath/energy_uj", \
  RUN+="/usr/bin/chmod g+r /sys$devpath/energy_uj"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=powercap

energy_uj is root-only because of CVE-2020-8694 (PLATYPUS), a power side-channel; opening it to the wheel group grants that group nothing it could not read through sudo, and touches only that file. You must be in wheel (re-login after adding yourself). Skip this on AMD or in a VM and set the energy source to Battery drain. setup-ii-p3drovfx.sh keeps the built binary across updates, so scripts/rust-helpers.sh stamps each binary with a hash of the sources it was built from: rust-helpers.sh list names the helpers, status shows whether each is current or stale, and outdated lists the ones worth rebuilding after an update (or after you edit app_stats_src/). The tablet family offers to build its helpers from inside the shell (Tablet Family).

What the sampler measures

It reads four sources at once — Hyprland's event socket (window changes the instant they happen), /proc/*/stat (CPU and memory, folded onto apps by walking the parent chain, so a browser's forty helpers count as one app), /proc/*/fdinfo/* (per-client GPU engine cycles from the xe driver) and the powercap RAPL counters — and writes one JSON file per local day to ~/.local/state/quickshell/user/app_stats/YYYY-MM-DD.json. The daemon knows only pids, window classes and counters; names and icons are resolved in QML, which is what keeps it tiny. Foreground time stops accruing while the screen is locked or the idle timer has fired — the shell tells the daemon, since the daemon cannot see either.

When the app closes, the parsed day files are released (the app is destroyed 30 s after closing); the current day stays cached so the limits keep counting.

Configuration

Key Default Meaning
appStats.enable false Run the sampler
appStats.sampleIntervalMs / flushIntervalMs 10000 / 60000 Poll and write periods
appStats.retentionDays / retentionMode 31 / previousMonth History kept
appStats.energySource auto auto, rapl, battery, none
appStats.idleTimeoutSec 300 Foreground pause on inactivity
appStats.trackHeadless / showHeadless true / false Background services
appStats.overlayEnabled true Whether the app exists (name kept from when it was an overlay)
screenTime.enable true The Limits tab and enforcement
screenTime.limits, schedules, alwaysAllowed [] Rules
screenTime.warnMinutes, warnLastMinute, notifyOnLimit, overdueReminderMinutes, autoCloseSeconds 5, on, on, 15, 0 Behaviour
screenTime.pinHash, pinForEdits "", off PIN

Under the hood

Piece Role
services/AppStats.qml Runs the sampler, reads day files into history, live lastSample, idle monitor
scripts/appStats/app_stats_src/ The Rust sampler
services/ScreenTimeLimits.qml Rules, live focus counting, blocking, grants
modules/ii/usage/ The app: Apps, Battery, limits/
modules/ii/screenTimeOverlay/ScreenTimeOverlay.qml The block screen
modules/ii/usage/UsageSemiDonut.qml, UsageColumnChart.qml, UsageActivityHeatmap.qml Charts also used by the [[Drive backup

Related pages

← Back to Home

Clone this wiki locally