Skip to content

Commit c371047

Browse files
committed
snapshot
1 parent 8a8f093 commit c371047

23 files changed

Lines changed: 893 additions & 179 deletions

File tree

home/linux/gui/base/noctalia/config/plugins/privacy-indicator/BarWidget.qml

Lines changed: 18 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ import QtQuick
22
import QtQuick.Controls
33
import QtQuick.Layouts
44
import Quickshell
5-
import Quickshell.Io
6-
import Quickshell.Services.Pipewire
75
import qs.Commons
8-
import qs.Modules.Bar.Extras
96
import qs.Services.UI
107
import qs.Widgets
118

@@ -26,22 +23,25 @@ Item {
2623
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
2724
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
2825

29-
property bool micActive: false
30-
property bool camActive: false
31-
property bool scrActive: false
32-
property var micApps: []
33-
property var camApps: []
34-
property var scrApps: []
26+
// Access main instance for state
27+
readonly property var mainInstance: pluginApi?.mainInstance
28+
29+
property bool micActive: mainInstance ? mainInstance.micActive : false
30+
property bool camActive: mainInstance ? mainInstance.camActive : false
31+
property bool scrActive: mainInstance ? mainInstance.scrActive : false
32+
property var micApps: mainInstance ? mainInstance.micApps : []
33+
property var camApps: mainInstance ? mainInstance.camApps : []
34+
property var scrApps: mainInstance ? mainInstance.scrApps : []
3535

3636
property var cfg: pluginApi?.pluginSettings || ({})
3737
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
3838

39-
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
40-
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
41-
property int iconSpacing: cfg.iconSpacing || Style.marginXS
42-
43-
property string activeColorKey: cfg.activeColor ?? defaults.activeColor
44-
property string inactiveColorKey: cfg.inactiveColor ?? defaults.inactiveColor
39+
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive ?? false
40+
property bool enableToast: cfg.enableToast ?? defaults.enableToast ?? true
41+
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins ?? false
42+
property int iconSpacing: cfg.iconSpacing ?? defaults.iconSpacing ?? 4
43+
property string activeColorKey: cfg.activeColor ?? defaults.activeColor ?? "primary"
44+
property string inactiveColorKey: cfg.inactiveColor ?? defaults.inactiveColor ?? "none"
4545

4646
readonly property color activeColor: Color.resolveColorKey(activeColorKey)
4747
readonly property color inactiveColor: inactiveColorKey === "none" ? Qt.alpha(Color.mOnSurfaceVariant, 0.3) : Color.resolveColorKey(inactiveColorKey)
@@ -63,156 +63,6 @@ Item {
6363
visible: root.isVisible
6464
opacity: root.isVisible ? 1.0 : 0.0
6565

66-
PwObjectTracker {
67-
objects: Pipewire.ready ? Pipewire.nodes.values : []
68-
}
69-
70-
Process {
71-
id: cameraCheckProcess
72-
running: false
73-
74-
command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && [ -n \"$(find /proc/[0-9]*/fd/ -lname \"$dev\" 2>/dev/null | head -n1)\" ] && echo \"active\" && exit 0; done; exit 1"]
75-
76-
onExited: (code, status) => {
77-
var isActive = code === 0;
78-
root.camActive = isActive;
79-
80-
if (isActive) {
81-
cameraAppsProcess.running = true;
82-
} else {
83-
root.camApps = [];
84-
}
85-
}
86-
}
87-
88-
Process {
89-
id: cameraAppsProcess
90-
running: false
91-
92-
command: ["sh", "-c", "for dev in /dev/video*; do [ -e \"$dev\" ] && for fd in /proc/[0-9]*/fd/*; do [ -L \"$fd\" ] && [ \"$(readlink \"$fd\" 2>/dev/null)\" = \"$dev\" ] && ps -p \"$(echo \"$fd\" | cut -d/ -f3)\" -o comm= 2>/dev/null; done; done | sort -u | tr '\\n' ',' | sed 's/,$//'"]
93-
94-
onExited: (code, status) => {
95-
if (stdout) {
96-
var appsString = stdout.trim();
97-
var apps = appsString.length > 0 ? appsString.split(',') : [];
98-
root.camApps = apps;
99-
} else {
100-
root.camApps = [];
101-
}
102-
}
103-
}
104-
105-
Timer {
106-
interval: 1000
107-
repeat: true
108-
running: true
109-
triggeredOnStart: true
110-
onTriggered: updatePrivacyState()
111-
}
112-
113-
function hasNodeLinks(node, links) {
114-
for (var i = 0; i < links.length; i++) {
115-
var link = links[i];
116-
if (link && (link.source === node || link.target === node)) {
117-
return true;
118-
}
119-
}
120-
return false;
121-
}
122-
123-
function getAppName(node) {
124-
return node.properties["application.name"] || node.nickname || node.name || "";
125-
}
126-
127-
function updateMicrophoneState(nodes, links) {
128-
var appNames = [];
129-
var isActive = false;
130-
131-
for (var i = 0; i < nodes.length; i++) {
132-
var node = nodes[i];
133-
if (!node || !node.isStream || !node.audio || node.isSink) continue;
134-
if (!hasNodeLinks(node, links) || !node.properties) continue;
135-
136-
var mediaClass = node.properties["media.class"] || "";
137-
if (mediaClass === "Stream/Input/Audio") {
138-
if (node.properties["stream.capture.sink"] === "true") {
139-
continue;
140-
}
141-
142-
isActive = true;
143-
var appName = getAppName(node);
144-
if (appName && appNames.indexOf(appName) === -1) {
145-
appNames.push(appName);
146-
}
147-
}
148-
}
149-
150-
root.micActive = isActive;
151-
root.micApps = appNames;
152-
}
153-
154-
function updateCameraState() {
155-
cameraCheckProcess.running = true;
156-
}
157-
158-
function isScreenShareNode(node) {
159-
if (!node.properties) {
160-
return false;
161-
}
162-
163-
var mediaClass = node.properties["media.class"] || "";
164-
165-
if (mediaClass.indexOf("Audio") >= 0) {
166-
return false;
167-
}
168-
169-
if (mediaClass.indexOf("Video") === -1) {
170-
return false;
171-
}
172-
173-
var mediaName = (node.properties["media.name"] || "").toLowerCase();
174-
175-
if (mediaName.match(/^(xdph-streaming|gsr-default|game capture|screen|desktop|display|cast|webrtc|v4l2)/) ||
176-
mediaName === "gsr-default_output" ||
177-
mediaName.match(/screen-cast|screen-capture|desktop-capture|monitor-capture|window-capture|game-capture/i)) {
178-
return true;
179-
}
180-
181-
return false;
182-
}
183-
184-
function updateScreenShareState(nodes, links) {
185-
var appNames = [];
186-
var isActive = false;
187-
188-
for (var i = 0; i < nodes.length; i++) {
189-
var node = nodes[i];
190-
if (!node || !hasNodeLinks(node, links) || !node.properties) continue;
191-
192-
if (isScreenShareNode(node)) {
193-
isActive = true;
194-
var appName = getAppName(node);
195-
if (appName && appNames.indexOf(appName) === -1) {
196-
appNames.push(appName);
197-
}
198-
}
199-
}
200-
201-
root.scrActive = isActive;
202-
root.scrApps = appNames;
203-
}
204-
205-
function updatePrivacyState() {
206-
if (!Pipewire.ready) return;
207-
208-
var nodes = Pipewire.nodes.values || [];
209-
var links = Pipewire.links.values || [];
210-
211-
updateMicrophoneState(nodes, links);
212-
updateCameraState();
213-
updateScreenShareState(nodes, links);
214-
}
215-
21666
function buildTooltip() {
21767
var parts = [];
21868

@@ -301,12 +151,14 @@ Item {
301151

302152
MouseArea {
303153
anchors.fill: parent
304-
acceptedButtons: Qt.RightButton
154+
acceptedButtons: Qt.RightButton | Qt.LeftButton
305155
hoverEnabled: true
306156

307157
onClicked: function (mouse) {
308158
if (mouse.button === Qt.RightButton) {
309159
PanelService.showContextMenu(contextMenu, root, screen);
160+
} else if (mouse.button === Qt.LeftButton) {
161+
if (pluginApi) pluginApi.openPanel(root.screen, root);
310162
}
311163
}
312164

0 commit comments

Comments
 (0)