Add xmusic tracker/audio player, xfiles media actions, ringtone volume & vibration fix
This commit is contained in:
+107
-28
@@ -26,6 +26,7 @@
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fcntl.h>
|
||||
#include <fstream>
|
||||
#include <poll.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -42,7 +43,7 @@ constexpr int kWinX = 0;
|
||||
constexpr int kWinY = kTopBarHeight;
|
||||
constexpr int kWinWidth = kScreenWidth;
|
||||
constexpr int kWinHeight = kScreenHeight - kTopBarHeight; // 296px flush below 24px dwm bar
|
||||
constexpr int kRowCount = 8;
|
||||
constexpr int kRowCount = 9;
|
||||
|
||||
// Nerd Font PUA icons matching sxmo_hook_icons.sh & dwm ("Fira Code, DejaVuSansM Nerd Font")
|
||||
constexpr const char* kIconSpeaker = "\xef\x80\xa8"; // U+F028 speaker
|
||||
@@ -239,12 +240,13 @@ class AlsaControl {
|
||||
enum class ControlId {
|
||||
SpeakerVol = 0,
|
||||
EarpieceVol = 1,
|
||||
Flashlight = 2,
|
||||
SoundMute = 3,
|
||||
MicMute = 4,
|
||||
RingerMode = 5,
|
||||
ScreenBright = 6,
|
||||
KbdBright = 7,
|
||||
RingVol = 2,
|
||||
RingerMode = 3,
|
||||
Flashlight = 4,
|
||||
SoundMute = 5,
|
||||
MicMute = 6,
|
||||
ScreenBright = 7,
|
||||
KbdBright = 8,
|
||||
};
|
||||
|
||||
struct ControlItem {
|
||||
@@ -282,31 +284,55 @@ class PhoneController {
|
||||
void refreshAll() {
|
||||
items_.clear();
|
||||
|
||||
// 1. Speaker volume (0..100%, mapped to ALSA RX3 Digital Volume 0..84)
|
||||
long rx3 = alsa_.getInteger("RX3 Digital Volume", 84);
|
||||
int spkPct = std::clamp(static_cast<int>(std::lround((rx3 * 100.0) / 84.0)), 0, 100);
|
||||
// 1. Speaker volume (0..100%, mapped to ALSA RX3 Digital Volume 60..92 + PipeWire 0..100%)
|
||||
int spkPct = readIntFile(getSxmoCfgDir() + "/speaker_vol", -1);
|
||||
if (spkPct < 0 || spkPct > 100) {
|
||||
long rx3 = alsa_.getInteger("RX3 Digital Volume", 92);
|
||||
if (rx3 <= 0) {
|
||||
spkPct = 0;
|
||||
} else if (rx3 >= 84) {
|
||||
spkPct = 100;
|
||||
} else {
|
||||
spkPct = std::clamp(static_cast<int>(std::lround(((rx3 - 60) * 100.0) / 32.0)), 5, 100);
|
||||
}
|
||||
}
|
||||
spkPct = (spkPct / 5) * 5;
|
||||
items_.push_back({ControlId::SpeakerVol, kIconSpeaker, kIconSoundOff,
|
||||
"Speaker", true, 0, 100, 5, spkPct});
|
||||
|
||||
// 2. Earpiece volume (0..100%, mapped to ALSA RX1 Digital Volume 0..84)
|
||||
// 2. Earpiece volume (0..100%, mapped to ALSA RX1 Digital Volume 58..90)
|
||||
long rx1 = alsa_.getInteger("RX1 Digital Volume", 84);
|
||||
int earPct = std::clamp(static_cast<int>(std::lround((rx1 * 100.0) / 84.0)), 0, 100);
|
||||
int earPct = 100;
|
||||
if (rx1 <= 0) {
|
||||
earPct = 0;
|
||||
} else if (rx1 < 84) {
|
||||
earPct = std::clamp(static_cast<int>(std::lround((rx1 * 100.0) / 84.0)), 5, 100);
|
||||
}
|
||||
earPct = (earPct / 5) * 5;
|
||||
items_.push_back({ControlId::EarpieceVol, kIconEarpiece, kIconEarpiece,
|
||||
"Earpiece", true, 0, 100, 5, earPct});
|
||||
|
||||
// 3. Flashlight on/off (toggle)
|
||||
// 3. Ringtone volume (0..100%, stored as SXMO_RINGVOL in ~/.config/sxmo/ringsettings)
|
||||
int ringPct = readRingVolume();
|
||||
items_.push_back({ControlId::RingVol, kIconBell, kIconBellSlash,
|
||||
"Ring Vol", true, 0, 100, 5, ringPct});
|
||||
|
||||
// 4. Ringer Mode (0=Ring+Vib, 1=Vibrate, 2=Silent, 3=DND)
|
||||
int ringerVal = readRingerMode();
|
||||
items_.push_back({ControlId::RingerMode, kIconBell, kIconBellSlash,
|
||||
"Ringer", false, 0, 3, 1, ringerVal});
|
||||
|
||||
// 5. Flashlight on/off (toggle)
|
||||
int torchCur = readIntFile(torchDir_ + "/brightness", 0);
|
||||
items_.push_back({ControlId::Flashlight, kIconFlashlight, kIconFlashlight,
|
||||
"Flashlight", false, 0, 1, 1, (torchCur > 0) ? 1 : 0});
|
||||
|
||||
// 4. Sound on/off (toggle)
|
||||
// 6. Sound on/off (toggle)
|
||||
bool spkOn = alsa_.getBoolean("SPK DAC Switch", true);
|
||||
items_.push_back({ControlId::SoundMute, kIconSoundOn, kIconSoundOff,
|
||||
"Sound", false, 0, 1, 1, spkOn ? 1 : 0});
|
||||
|
||||
// 5. Microphone on/off (toggle)
|
||||
// 7. Microphone on/off (toggle)
|
||||
unsigned int dec1 = alsa_.getEnum("DEC1 MUX", 2);
|
||||
if (dec1 > 0) {
|
||||
savedMicMux_ = dec1;
|
||||
@@ -317,18 +343,13 @@ class PhoneController {
|
||||
items_.push_back({ControlId::MicMute, kIconMicOn, kIconMicOff,
|
||||
"Microphone", false, 0, 1, 1, (dec1 > 0) ? 1 : 0});
|
||||
|
||||
// 6. Ringer Mode (0=Ring+Vib, 1=Vibrate, 2=Silent, 3=DND)
|
||||
int ringerVal = readRingerMode();
|
||||
items_.push_back({ControlId::RingerMode, kIconBell, kIconBellSlash,
|
||||
"Ringer", false, 0, 3, 1, ringerVal});
|
||||
|
||||
// 7. Screen brightness (slider 1..screenMax_)
|
||||
// 8. Screen brightness (slider 1..screenMax_)
|
||||
int scrCur = std::clamp(readIntFile(backlightDir_ + "/brightness", screenMax_), 1, screenMax_);
|
||||
int scrStep = std::max(1, screenMax_ / 14);
|
||||
items_.push_back({ControlId::ScreenBright, kIconBrightness, kIconBrightness,
|
||||
"Screen", true, 1, screenMax_, scrStep, scrCur});
|
||||
|
||||
// 7. Keyboard brightness (slider if max_brightness > 1, toggle otherwise)
|
||||
// 9. Keyboard brightness (slider if max_brightness > 1, toggle otherwise)
|
||||
int kbdCur = std::clamp(readIntFile(kbdDir_ + "/brightness", 0), 0, kbdMax_);
|
||||
if (kbdSupportsSlider_) {
|
||||
int kbdStep = std::max(1, kbdMax_ / 10);
|
||||
@@ -395,25 +416,81 @@ class PhoneController {
|
||||
return 0; // Ring + Vibrate
|
||||
}
|
||||
|
||||
static int readRingVolume() {
|
||||
std::ifstream ifs(getSxmoCfgDir() + "/ringsettings");
|
||||
std::string line;
|
||||
while (std::getline(ifs, line)) {
|
||||
auto eq = line.find('=');
|
||||
if (eq == std::string::npos) continue;
|
||||
std::string k = line.substr(0, eq);
|
||||
std::string v = line.substr(eq + 1);
|
||||
if (k == "SXMO_RINGVOL") {
|
||||
int val = std::clamp(std::atoi(v.c_str()), 0, 100);
|
||||
return (val / 5) * 5;
|
||||
}
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
static void writeRingVolume(int ringVol) {
|
||||
std::string cfg = getSxmoCfgDir();
|
||||
::mkdir(cfg.c_str(), 0755);
|
||||
std::string path = cfg + "/ringsettings";
|
||||
int ringTime = 20;
|
||||
int ringLoops = 10;
|
||||
int vibStrength = 2;
|
||||
{
|
||||
std::ifstream ifs(path);
|
||||
std::string line;
|
||||
while (std::getline(ifs, line)) {
|
||||
auto eq = line.find('=');
|
||||
if (eq == std::string::npos) continue;
|
||||
std::string k = line.substr(0, eq);
|
||||
int val = std::atoi(line.substr(eq + 1).c_str());
|
||||
if (k == "SXMO_RINGTIME" && val >= 5 && val <= 120) ringTime = val;
|
||||
else if (k == "SXMO_RINGNUMBER" && val >= 1 && val <= 100) ringLoops = val;
|
||||
else if (k == "SXMO_VIBRATE_STRENGTH" && val >= 1 && val <= 3) vibStrength = val;
|
||||
}
|
||||
}
|
||||
std::ofstream ofs(path, std::ios::trunc);
|
||||
if (ofs) {
|
||||
ofs << "SXMO_RINGTIME=" << ringTime << "\n";
|
||||
ofs << "SXMO_RINGNUMBER=" << ringLoops << "\n";
|
||||
ofs << "SXMO_VIBRATE_STRENGTH=" << vibStrength << "\n";
|
||||
ofs << "SXMO_RINGVOL=" << std::clamp(ringVol, 0, 100) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void apply(ControlItem& it) {
|
||||
switch (it.id) {
|
||||
case ControlId::SpeakerVol: {
|
||||
long hw = std::lround((it.value * 84.0) / 100.0);
|
||||
std::string cfg = getSxmoCfgDir();
|
||||
::mkdir(cfg.c_str(), 0755);
|
||||
writeIntFile(cfg + "/speaker_vol", it.value);
|
||||
long hw = (it.value <= 0) ? 0 : (60 + std::lround((it.value * 32.0) / 100.0));
|
||||
if (it.value > 0) {
|
||||
alsa_.setBoolean("SPK DAC Switch", true);
|
||||
}
|
||||
alsa_.setInteger("RX3 Digital Volume", hw);
|
||||
char cmd[128];
|
||||
char cmd[160];
|
||||
std::snprintf(
|
||||
cmd, sizeof(cmd),
|
||||
"wpctl set-mute @DEFAULT_AUDIO_SINK@ %d >/dev/null 2>&1; "
|
||||
"wpctl set-volume @DEFAULT_AUDIO_SINK@ %d%% >/dev/null 2>&1; "
|
||||
"sxmo_hook_statusbar.sh audio >/dev/null 2>&1",
|
||||
it.value);
|
||||
"sxmo_hook_statusbar.sh volume >/dev/null 2>&1",
|
||||
(it.value <= 0) ? 1 : 0, it.value);
|
||||
runAsyncCmd(cmd);
|
||||
break;
|
||||
}
|
||||
case ControlId::EarpieceVol: {
|
||||
long hw = std::lround((it.value * 84.0) / 100.0);
|
||||
long hw = (it.value <= 0) ? 0 : (58 + std::lround((it.value * 32.0) / 100.0));
|
||||
alsa_.setInteger("RX1 Digital Volume", hw);
|
||||
break;
|
||||
}
|
||||
case ControlId::RingVol: {
|
||||
writeRingVolume(it.value);
|
||||
break;
|
||||
}
|
||||
case ControlId::Flashlight: {
|
||||
int v = it.value ? torchMax_ : 0;
|
||||
if (!writeIntFile(torchDir_ + "/brightness", v)) {
|
||||
@@ -994,7 +1071,9 @@ static int xdrawer_run_main(int argc, char** argv) {
|
||||
case XK_4:
|
||||
case XK_5:
|
||||
case XK_6:
|
||||
case XK_7: {
|
||||
case XK_7:
|
||||
case XK_8:
|
||||
case XK_9: {
|
||||
size_t idx = static_cast<size_t>(sym - XK_1);
|
||||
if (idx < count) {
|
||||
selected = idx;
|
||||
|
||||
Reference in New Issue
Block a user