mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
bluetooth: integrate with DMS API v9 - Supports proper pairing with an agent & pin, passcode, etc.
This commit is contained in:
@@ -6,6 +6,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Bluetooth
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
@@ -15,6 +16,7 @@ Singleton {
|
||||
readonly property bool enabled: (adapter && adapter.enabled) ?? false
|
||||
readonly property bool discovering: (adapter && adapter.discovering) ?? false
|
||||
readonly property var devices: adapter ? adapter.devices : null
|
||||
readonly property bool enhancedPairingAvailable: DMSService.dmsAvailable && DMSService.apiVersion >= 9 && DMSService.capabilities.includes("bluetooth")
|
||||
readonly property bool connected: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return false
|
||||
@@ -173,6 +175,25 @@ Singleton {
|
||||
device.connect()
|
||||
}
|
||||
|
||||
function pairDevice(device, callback) {
|
||||
if (!device) {
|
||||
if (callback) callback({error: "Invalid device"})
|
||||
return
|
||||
}
|
||||
|
||||
// The DMS backend actually implements a bluez agent, so we can pair anything
|
||||
if (enhancedPairingAvailable) {
|
||||
const devicePath = getDevicePath(device)
|
||||
DMSService.bluetoothPair(devicePath, callback)
|
||||
return
|
||||
}
|
||||
|
||||
// Quickshell does not implement a bluez agent, so we can try to pair but only with devices that don't require a passcode
|
||||
device.trusted = true
|
||||
device.connect()
|
||||
if (callback) callback({success: true})
|
||||
}
|
||||
|
||||
function getCardName(device) {
|
||||
if (!device) {
|
||||
return ""
|
||||
@@ -180,6 +201,14 @@ Singleton {
|
||||
return `bluez_card.${device.address.replace(/:/g, "_")}`
|
||||
}
|
||||
|
||||
function getDevicePath(device) {
|
||||
if (!device || !device.address) {
|
||||
return ""
|
||||
}
|
||||
const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0"
|
||||
return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}`
|
||||
}
|
||||
|
||||
function isAudioDevice(device) {
|
||||
if (!device) {
|
||||
return false
|
||||
|
||||
@@ -42,6 +42,7 @@ Singleton {
|
||||
signal loginctlEvent(var event)
|
||||
signal capabilitiesReceived()
|
||||
signal credentialsRequest(var data)
|
||||
signal bluetoothPairingRequest(var data)
|
||||
|
||||
Component.onCompleted: {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
@@ -217,7 +218,10 @@ Singleton {
|
||||
|
||||
function sendSubscribeRequest() {
|
||||
const request = {
|
||||
"method": "subscribe"
|
||||
"method": "subscribe",
|
||||
"params": {
|
||||
"services": ["bluetooth", "bluetooth.pairing"]
|
||||
}
|
||||
}
|
||||
|
||||
if (verboseLogs) {
|
||||
@@ -270,6 +274,8 @@ Singleton {
|
||||
} else {
|
||||
loginctlStateUpdate(data)
|
||||
}
|
||||
} else if (service === "bluetooth.pairing") {
|
||||
bluetoothPairingRequest(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,4 +414,48 @@ Singleton {
|
||||
function unlockSession(callback) {
|
||||
sendRequest("loginctl.unlock", null, callback)
|
||||
}
|
||||
|
||||
function bluetoothPair(devicePath, callback) {
|
||||
sendRequest("bluetooth.pair", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function bluetoothConnect(devicePath, callback) {
|
||||
sendRequest("bluetooth.connect", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function bluetoothDisconnect(devicePath, callback) {
|
||||
sendRequest("bluetooth.disconnect", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function bluetoothRemove(devicePath, callback) {
|
||||
sendRequest("bluetooth.remove", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function bluetoothTrust(devicePath, callback) {
|
||||
sendRequest("bluetooth.trust", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function bluetoothSubmitPairing(token, secrets, accept, callback) {
|
||||
sendRequest("bluetooth.pairing.submit", {
|
||||
"token": token,
|
||||
"secrets": secrets,
|
||||
"accept": accept
|
||||
}, callback)
|
||||
}
|
||||
|
||||
function bluetoothCancelPairing(token, callback) {
|
||||
sendRequest("bluetooth.pairing.cancel", {
|
||||
"token": token
|
||||
}, callback)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
pragma ComponentBehavior
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
@@ -640,7 +640,7 @@ Singleton {
|
||||
const enrichedToplevel = {
|
||||
"appId": bestMatch.appId,
|
||||
"title": bestMatch.title,
|
||||
"activated": bestMatch.activated,
|
||||
"activated": niriWindow.is_focused ?? false,
|
||||
"niriWindowId": niriWindow.id,
|
||||
"niriWorkspaceId": niriWindow.workspace_id,
|
||||
"activate": function () {
|
||||
@@ -726,7 +726,7 @@ Singleton {
|
||||
const enrichedToplevel = {
|
||||
"appId": bestMatch.appId,
|
||||
"title": bestMatch.title,
|
||||
"activated": bestMatch.activated,
|
||||
"activated": niriWindow.is_focused ?? false,
|
||||
"niriWindowId": niriWindow.id,
|
||||
"niriWorkspaceId": niriWindow.workspace_id,
|
||||
"activate": function () {
|
||||
@@ -753,12 +753,10 @@ Singleton {
|
||||
}
|
||||
|
||||
function generateNiriLayoutConfig() {
|
||||
const niriSocket = Quickshell.env("NIRI_SOCKET")
|
||||
if (!niriSocket || niriSocket.length === 0)
|
||||
return
|
||||
if (configGenerationPending)
|
||||
if (!CompositorService.isNiri || configGenerationPending)
|
||||
return
|
||||
|
||||
suppressNextToast()
|
||||
configGenerationPending = true
|
||||
configGenerationDebounce.restart()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user