Skip to content

feat: add hypr-screen-mirror#66

Merged
ItsLemmy merged 7 commits into
noctalia-dev:mainfrom
Profiidev:feat/hypr-screen-mirror
Jul 22, 2026
Merged

feat: add hypr-screen-mirror#66
ItsLemmy merged 7 commits into
noctalia-dev:mainfrom
Profiidev:feat/hypr-screen-mirror

Conversation

@Profiidev

Copy link
Copy Markdown
Contributor

Plugin

  • Id: profidev/hypr-screen-mirror
  • New plugin
  • Update to an existing plugin (version bumped in plugin.toml)

What it does

Widget/Panel to easily control mirroring of Hyprland monitors

External dependencies

  • hyprctl for querying monitor information and controlling mirror state
  • socat to read the Hyprland event socket for monitor changes

Testing

  • Tested on Niri
  • Tested on Hyprland
  • Tested on Sway
  • Tested on another compositor:
  • Noctalia version tested against: 5.0.0
  • Plugin API level: 5

Screenshots / Videos

screenshot_20260720_173505-region

Checklist

  • The directory name matches the part of id after the / in plugin.toml exactly.
  • It ships plugin.toml, README.md, thumbnail.webp, and translations/en.json.
  • README.md follows the
    README template, documents
    every entry id and dependency, and includes exact panel IPC commands and launcher prefixes where applicable.
  • I created thumbnail.webp with the thumbnail generator.
  • version follows semver and is bumped in this PR; plugin_api is the oldest API level this plugin requires.
  • Every non-English translation in this PR uses a locale supported by Noctalia core, and I can read, write, and
    understand that language well enough to review and maintain it (no unreviewed machine/LLM translations).
  • I did not edit catalog.toml; CI generates it.
  • This PR touches exactly one plugin directory.

Code review attestation

Plugins run as trusted, unsandboxed Luau in the user's session. Confirm:

  • The code is readable and not obfuscated, minified, or generated.
  • It does not download and execute remote code.
  • Every network call, filesystem write, and spawned process is something the description above accounts for.
  • I have the right to publish this code under the license declared in plugin.toml.

@ItsLemmy

Copy link
Copy Markdown
Contributor

• 1. blocking - hypr-screen-mirror/service.luau:104

The Hyprland socket path is inserted into a shell command without quoting. Monitor names are likewise inserted directly into nested shell and Lua command strings at hypr-screen-mirror/service.luau:122 and hypr-screen-mirror/service.luau:139. A crafted socket path or monitor name containing shell meta characters or quotes can alter the command and execute arbitrary shell code in the user session. Hyprland permits custom names for virtual outputs,
so monitor names cannot safely be treated as fixed connector identifiers. Quote shell arguments and separately escape values embedded in the Lua expression, or avoid shell-string construction.

  1. blocking - hypr-screen-mirror/service.luau:55

Hyprland 0.55 serializes monitor id as a JSON number and mirrorOf as a JSON string, so this strict comparison never identifies the mirror source. The code then sets isMirroring at hypr-screen-mirror/service.luau:62, which invokes the command watcher at hypr-screen-mirror/service.luau:149. Discovering an existing mirror therefore issues a new mirroring command using a stale or default source selection instead of only recording observed state. Monitor
events can repeat this behavior. Separate observed state from action requests, normalize the ID types, and explicitly publish false when no mirror exists.

  1. non-blocking - hypr-screen-mirror/service.luau:13

When JSON decoding fails or returns a non-table value, the callback displays a notification but continues into ipairs(msg) at hypr-screen-mirror/service.luau:20. This raises another runtime error and aborts the refresh. Return after reporting the decode failure.

  1. non-blocking - hypr-screen-mirror/service.luau:9

The timeout paths reference notification.timed_out, also at hypr-screen-mirror/service.luau:126 and hypr-screen-mirror/service.luau:143, but the catalog defines notification.timeout at hypr-screen-mirror/translations/en.json:10. Timeout notifications therefore display a missing key instead of the intended message.

Hyprland’s official documentation confirms that virtual outputs may have optional custom names: Using hyprctl
(https://wiki.hypr.land/Configuring/Advanced-and-Cool/Using-hyprctl/).

@ItsLemmy
ItsLemmy marked this pull request as draft July 21, 2026 01:58
@Profiidev
Profiidev marked this pull request as ready for review July 21, 2026 06:50
@Profiidev

Copy link
Copy Markdown
Contributor Author

I hope the "Separate observed state from action requests" part is fixed because I didn't really understand what you meant by that or how to fix it

@ItsLemmy

Copy link
Copy Markdown
Contributor

Can you check if everything still works as expected with my latest commit. This should fix the last blocker.

@ItsLemmy
ItsLemmy marked this pull request as draft July 21, 2026 17:44
@Profiidev

Copy link
Copy Markdown
Contributor Author

Thanks for the fix. Everything is still working for me

@Profiidev
Profiidev marked this pull request as ready for review July 21, 2026 18:20
@ItsLemmy
ItsLemmy merged commit 8a3bb49 into noctalia-dev:main Jul 22, 2026
1 check passed
@Profiidev
Profiidev deleted the feat/hypr-screen-mirror branch July 22, 2026 04:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants