| 1 | // This policy is independent of Shell so lifecycle and authorization can be tested without a desktop. |
| 2 | export const CLIENT_NAMES = [ |
| 3 | "com.t3tools.T3Code.SnapShot", |
| 4 | "com.t3tools.T3Code.Development.SnapShot", |
| 5 | ]; |
| 6 | |
| 7 | export function isWaylandSession(meta) { |
| 8 | // GNOME 50 removed the X11 compositor and this API. GNOME 45–49 still need the check. |
| 9 | return typeof meta.is_wayland_compositor !== "function" || meta.is_wayland_compositor(); |
| 10 | } |
| 11 | |
| 12 | export class CaptureService { |
| 13 | constructor({ getNameOwner, isAvailable, takeSnapshot, getProcessId, beginFeedback }) { |
| 14 | this._getNameOwner = getNameOwner; |
| 15 | this._isAvailable = isAvailable; |
| 16 | this._takeSnapshot = takeSnapshot; |
| 17 | this._getProcessId = getProcessId; |
| 18 | this._beginFeedback = beginFeedback; |
| 19 | this._enabled = true; |
| 20 | this._busy = false; |
| 21 | } |
| 22 | |
| 23 | disable() { |
| 24 | this._enabled = false; |
| 25 | } |
| 26 | |
| 27 | _checkSession() { |
| 28 | if (!this._enabled || !this._isAvailable()) { |
| 29 | throw new Error("SnapShots are unavailable in this session."); |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | async capture(sender, options) { |
| 34 | this._checkSession(); |
| 35 | if (this._busy) throw new Error("A snapshot is already in progress."); |
| 36 | this._busy = true; |
| 37 | try { |
| 38 | let allowed = false; |
| 39 | for (const name of CLIENT_NAMES) { |
| 40 | const owner = await this._getNameOwner(name); |
| 41 | if (owner === sender) { |
| 42 | allowed = true; |
| 43 | break; |
| 44 | } |
| 45 | } |
| 46 | if (!allowed) throw new Error("Only The Knife may request a snapshot."); |
| 47 | const pid = options ? await this._getProcessId(sender) : undefined; |
| 48 | this._checkSession(); |
| 49 | const snapshot = await this._takeSnapshot(options?.animate ?? false); |
| 50 | // Never deliver pixels after locking the session or disabling the extension. |
| 51 | this._checkSession(); |
| 52 | if (options) { |
| 53 | return { |
| 54 | ...snapshot, |
| 55 | animationStarted: this._beginFeedback(sender, pid, snapshot, options), |
| 56 | }; |
| 57 | } |
| 58 | return snapshot; |
| 59 | } finally { |
| 60 | this._busy = false; |
| 61 | } |
| 62 | } |
| 63 | } |