Fix SIM2 QMI UIM provisioning, auto-enable ModemManager, PIN auto-prompt, call audio, and Dunst clearing
This commit is contained in:
@@ -62,12 +62,15 @@ struct SimSlotInfo {
|
||||
|
||||
bool needsPin() const {
|
||||
return state == "present" &&
|
||||
(pin1State == "enabled-not-verified" || appState == "pin1");
|
||||
(pin1State == "enabled-not-verified" ||
|
||||
appState.rfind("pin1", 0) == 0);
|
||||
}
|
||||
|
||||
bool needsPuk() const {
|
||||
return state == "present" &&
|
||||
(pin1State == "blocked" || appState == "puk1");
|
||||
(pin1State == "blocked" ||
|
||||
appState.rfind("puk1", 0) == 0 ||
|
||||
appState == "pin1-blocked");
|
||||
}
|
||||
|
||||
bool isPinEnabled() const {
|
||||
@@ -88,6 +91,13 @@ struct ModemStatusData {
|
||||
std::string mmFailedReason;
|
||||
std::string mmPowerState = "off";
|
||||
std::string mmUnlockRequired;
|
||||
std::string mmRegState;
|
||||
std::string nasRegState;
|
||||
std::string nasOperator;
|
||||
std::string nasMcc;
|
||||
std::string nasMnc;
|
||||
std::string nasRoaming;
|
||||
std::string nasRadio;
|
||||
int mmPinRetries = -1;
|
||||
int mmPukRetries = -1;
|
||||
std::string operatorName;
|
||||
@@ -103,6 +113,56 @@ struct ModemStatusData {
|
||||
std::string simOperatorName;
|
||||
std::string currentModes;
|
||||
int modePresetIdx = 0;
|
||||
|
||||
bool isNetworkRegistered() const {
|
||||
return mmRegState == "home" || mmRegState == "roaming" ||
|
||||
nasRegState == "registered" ||
|
||||
mmState == "registered" || mmState == "connected";
|
||||
}
|
||||
|
||||
bool isNetworkSearching() const {
|
||||
return mmRegState == "searching" || nasRegState == "searching" ||
|
||||
mmState == "searching" || mmState == "enabling" ||
|
||||
mmState == "connecting";
|
||||
}
|
||||
|
||||
std::string regStatusLabel() const {
|
||||
if (slots[0].needsPuk() || slots[1].needsPuk() ||
|
||||
mmUnlockRequired == "sim-puk") {
|
||||
return "SIM PUK Required";
|
||||
}
|
||||
if (slots[0].needsPin() || slots[1].needsPin() ||
|
||||
mmUnlockRequired == "sim-pin" || mmState == "locked") {
|
||||
return "SIM PIN Required";
|
||||
}
|
||||
if (mmRegState == "home" ||
|
||||
(nasRegState == "registered" && nasRoaming != "on")) {
|
||||
return "Registered (Home)";
|
||||
}
|
||||
if (mmRegState == "roaming" ||
|
||||
(nasRegState == "registered" && nasRoaming == "on")) {
|
||||
return "Registered (Roaming)";
|
||||
}
|
||||
if (mmState == "connected" || mmState == "registered") {
|
||||
return "Registered";
|
||||
}
|
||||
if (isNetworkSearching()) {
|
||||
return "Searching...";
|
||||
}
|
||||
if (mmRegState == "denied" || nasRegState == "registration-denied") {
|
||||
return "Registration Denied";
|
||||
}
|
||||
if (slots[0].state != "present" && slots[1].state != "present") {
|
||||
return "No SIM Inserted";
|
||||
}
|
||||
if (primaryGwSlot == 0) {
|
||||
return "SIM Not Activated";
|
||||
}
|
||||
if (mmState == "disabled") {
|
||||
return "Modem Disabled";
|
||||
}
|
||||
return "Not Registered";
|
||||
}
|
||||
};
|
||||
|
||||
struct RadioModePreset {
|
||||
@@ -201,6 +261,12 @@ ModemStatusData queryModemAndSimStatus() {
|
||||
if (!uimKv["PRIMARY_GW_SLOT"].empty()) {
|
||||
d.primaryGwSlot = std::atoi(uimKv["PRIMARY_GW_SLOT"].c_str());
|
||||
}
|
||||
d.nasRegState = uimKv["NAS_REG_STATE"];
|
||||
d.nasOperator = uimKv["NAS_OPERATOR"];
|
||||
d.nasMcc = uimKv["NAS_MCC"];
|
||||
d.nasMnc = uimKv["NAS_MNC"];
|
||||
d.nasRoaming = uimKv["NAS_ROAMING"];
|
||||
d.nasRadio = uimKv["NAS_RADIO"];
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
std::string pfx = "SLOT" + std::to_string(i + 1) + "_";
|
||||
@@ -244,6 +310,7 @@ ModemStatusData queryModemAndSimStatus() {
|
||||
d.mmFailedReason = cleanMmVal(mmKv["modem.generic.state-failed-reason"]);
|
||||
d.mmPowerState = cleanMmVal(mmKv["modem.generic.power-state"]);
|
||||
d.mmUnlockRequired = cleanMmVal(mmKv["modem.generic.unlock-required"]);
|
||||
d.mmRegState = cleanMmVal(mmKv["modem.3gpp.registration-state"]);
|
||||
d.operatorName = cleanMmVal(mmKv["modem.3gpp.operator-name"]);
|
||||
d.operatorCode = cleanMmVal(mmKv["modem.3gpp.operator-code"]);
|
||||
d.accessTech = cleanMmVal(mmKv["modem.generic.access-technologies.value[1]"]);
|
||||
@@ -309,6 +376,16 @@ ModemStatusData queryModemAndSimStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
if (d.operatorName.empty() && !d.nasOperator.empty()) {
|
||||
d.operatorName = d.nasOperator;
|
||||
}
|
||||
if (d.operatorCode.empty() && !d.nasMcc.empty() && !d.nasMnc.empty()) {
|
||||
d.operatorCode = d.nasMcc + d.nasMnc;
|
||||
}
|
||||
if (d.accessTech.empty() && !d.nasRadio.empty() && d.nasRadio != "none") {
|
||||
d.accessTech = d.nasRadio;
|
||||
}
|
||||
|
||||
// Sync ModemManager lock info into active slot if QMI didn't report retries
|
||||
int actIdx = (d.primaryGwSlot >= 1 && d.primaryGwSlot <= 2)
|
||||
? (d.primaryGwSlot - 1)
|
||||
@@ -395,8 +472,8 @@ int runModemApp(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeIntFile(daemonPidPath, static_cast<int>(::getpid()));
|
||||
int fifoFd = setupPluginDaemonFifo("modem");
|
||||
writeIntFile(daemonPidPath, static_cast<int>(::getpid()));
|
||||
|
||||
struct sigaction sa {};
|
||||
sa.sa_handler = handleSignal;
|
||||
@@ -702,10 +779,24 @@ int runModemApp(int argc, char** argv) {
|
||||
line2 = "LOCKED (Enter PIN)";
|
||||
line2Col = &colOrange;
|
||||
} else if (s.isActiveProvisioned) {
|
||||
std::string op = status.operatorName.empty() ? "Ready" : status.operatorName;
|
||||
if (!status.ownNumber.empty()) op += " " + status.ownNumber;
|
||||
line2 = op;
|
||||
line2Col = &colGreen;
|
||||
std::string reg = status.regStatusLabel();
|
||||
if (!status.operatorName.empty()) {
|
||||
reg += " - " + status.operatorName;
|
||||
}
|
||||
if (!status.accessTech.empty()) {
|
||||
reg += " [" + status.accessTech + "]";
|
||||
}
|
||||
line2 = reg;
|
||||
if (status.isNetworkRegistered()) {
|
||||
line2Col = &colGreen;
|
||||
} else if (status.isNetworkSearching()) {
|
||||
line2Col = &colOrange;
|
||||
} else {
|
||||
line2Col = &colRed;
|
||||
}
|
||||
} else if (status.primaryGwSlot == 0) {
|
||||
line2 = "Present (Unactivated - Press Select)";
|
||||
line2Col = &colOrange;
|
||||
} else {
|
||||
line2 = "Present (Standby " + s.appType + ")";
|
||||
line2Col = &colBlue;
|
||||
@@ -726,6 +817,9 @@ int runModemApp(int argc, char** argv) {
|
||||
else if (pState == "blocked") pState = "PUK Req";
|
||||
line3 = pState + " (PIN:" + std::to_string(s.pin1Retries) +
|
||||
" PUK:" + std::to_string(s.puk1Retries) + ")";
|
||||
if (s.isActiveProvisioned && !status.ownNumber.empty()) {
|
||||
line3 += " " + status.ownNumber;
|
||||
}
|
||||
} else {
|
||||
line3 = "Insert nano-SIM & restart/switch";
|
||||
}
|
||||
@@ -736,8 +830,18 @@ int runModemApp(int argc, char** argv) {
|
||||
// Quick Action Rows below the 2 SIM cards (4 rows, 24px each)
|
||||
int actSlot = (simRowSel == 1) ? 2 : 1;
|
||||
int otherSlot = (status.preferredSlot == 1) ? 2 : 1;
|
||||
if (status.primaryGwSlot == 0) {
|
||||
if (status.slots[1].state == "present" && status.slots[0].state != "present") {
|
||||
otherSlot = 2;
|
||||
} else if (status.slots[0].state == "present" && status.slots[1].state != "present") {
|
||||
otherSlot = 1;
|
||||
}
|
||||
}
|
||||
std::string quickRows[4] = {
|
||||
std::string(kIconRefresh) + " Switch Active to SIM " + std::to_string(otherSlot),
|
||||
std::string(kIconRefresh) +
|
||||
(status.primaryGwSlot == 0
|
||||
? (" Activate SIM " + std::to_string(otherSlot))
|
||||
: (" Switch Active to SIM " + std::to_string(otherSlot))),
|
||||
std::string(kIconUnlock) + " Unlock SIM (PIN / PUK)",
|
||||
std::string(kIconLock) + " Enable / Disable SIM PIN",
|
||||
std::string(kIconKey) + " Change SIM PIN Code",
|
||||
@@ -762,29 +866,31 @@ int runModemApp(int argc, char** argv) {
|
||||
XSetForeground(dpy, gc, pt.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 4, contentY, kWinWidth - 9, 101);
|
||||
|
||||
std::string stStr = status.mmPresent ? status.mmState : "nomodem";
|
||||
if (!status.mmFailedReason.empty()) {
|
||||
stStr += " (" + status.mmFailedReason + ")";
|
||||
}
|
||||
std::string regStr = status.regStatusLabel();
|
||||
XftColor* stCol = &colRed;
|
||||
if (status.mmState == "connected" || status.mmState == "registered") {
|
||||
if (status.isNetworkRegistered()) {
|
||||
stCol = &colGreen;
|
||||
} else if (status.mmState == "searching" || status.mmState == "connecting") {
|
||||
} else if (status.isNetworkSearching()) {
|
||||
stCol = &colOrange;
|
||||
}
|
||||
drawPango(layoutMain, stCol, 10, contentY + 2, 22,
|
||||
"State: " + stStr, 185);
|
||||
"Net: " + regStr, 185);
|
||||
drawSignalBars(kWinWidth - 32, contentY + 6, status.signalQuality);
|
||||
|
||||
std::string opLine = "Operator: " +
|
||||
(status.operatorName.empty() ? "--" : status.operatorName);
|
||||
if (!status.operatorCode.empty() &&
|
||||
status.operatorName != status.operatorCode) {
|
||||
opLine += " (" + status.operatorCode + ")";
|
||||
}
|
||||
if (!status.accessTech.empty()) {
|
||||
opLine += " [" + status.accessTech + "]";
|
||||
}
|
||||
drawPango(layoutSmall, &colLight, 10, contentY + 24, 18, opLine, 220);
|
||||
|
||||
std::string sigLine = "Signal: " + std::to_string(status.signalQuality) +
|
||||
"% | Slot: SIM " +
|
||||
std::string stStr = status.mmPresent ? status.mmState : "nomodem";
|
||||
std::string sigLine = "Modem: " + stStr + " | Sig: " +
|
||||
std::to_string(status.signalQuality) + "% | SIM " +
|
||||
(status.primaryGwSlot > 0 ? std::to_string(status.primaryGwSlot) : "--");
|
||||
drawPango(layoutSmall, &colLight, 10, contentY + 42, 18, sigLine, 220);
|
||||
|
||||
@@ -1090,6 +1196,15 @@ int runModemApp(int argc, char** argv) {
|
||||
};
|
||||
|
||||
auto showWindow = [&](const std::string& arg = "") {
|
||||
std::string a = toLowerStr(trimStr(arg));
|
||||
if (visible &&
|
||||
(modal == ModalMode::VerifyPin || modal == ModalMode::UnblockPuk) &&
|
||||
(a == "unlock" || a == "pin" || a == "puk")) {
|
||||
XRaiseWindow(dpy, win);
|
||||
grabKeys();
|
||||
render();
|
||||
return;
|
||||
}
|
||||
closeOtherPlugins("modem");
|
||||
refreshData(true);
|
||||
applyOpenArg(arg);
|
||||
@@ -1308,16 +1423,36 @@ int runModemApp(int argc, char** argv) {
|
||||
|
||||
auto triggerSimRowAction = [&](int row) {
|
||||
if (row == 0 || row == 1) {
|
||||
targetSlot = row + 1;
|
||||
actionSel = 0;
|
||||
modal = ModalMode::SimActions;
|
||||
int sNum = row + 1;
|
||||
const auto& s = status.slots[row];
|
||||
if (s.needsPin() || s.needsPuk()) {
|
||||
openPinOrPukModalForSlot(sNum);
|
||||
} else if (s.state == "present" && !s.isActiveProvisioned) {
|
||||
switchSimSlotNow(sNum);
|
||||
} else {
|
||||
targetSlot = sNum;
|
||||
actionSel = 0;
|
||||
modal = ModalMode::SimActions;
|
||||
}
|
||||
} else if (row == 2) {
|
||||
int otherSlot = (status.preferredSlot == 1) ? 2 : 1;
|
||||
if (status.primaryGwSlot == 0) {
|
||||
if (status.slots[1].state == "present" && status.slots[0].state != "present") {
|
||||
otherSlot = 2;
|
||||
} else if (status.slots[0].state == "present" && status.slots[1].state != "present") {
|
||||
otherSlot = 1;
|
||||
}
|
||||
}
|
||||
switchSimSlotNow(otherSlot);
|
||||
} else if (row == 3) {
|
||||
int slot = (status.primaryGwSlot >= 1 && status.primaryGwSlot <= 2)
|
||||
? status.primaryGwSlot
|
||||
: status.preferredSlot;
|
||||
if (status.slots[0].needsPin() || status.slots[0].needsPuk()) {
|
||||
slot = 1;
|
||||
} else if (status.slots[1].needsPin() || status.slots[1].needsPuk()) {
|
||||
slot = 2;
|
||||
}
|
||||
openPinOrPukModalForSlot(slot);
|
||||
} else if (row == 4) {
|
||||
targetSlot = (status.primaryGwSlot >= 1 && status.primaryGwSlot <= 2)
|
||||
@@ -1446,14 +1581,18 @@ int runModemApp(int argc, char** argv) {
|
||||
ussdResponse.clear();
|
||||
ussdWaitingReply = false;
|
||||
} else if (radioRowSel == 2) {
|
||||
bool powerOn = (status.mmPowerState == "on" ||
|
||||
status.mmState == "registered" ||
|
||||
status.mmState == "connected" ||
|
||||
status.mmState == "searching");
|
||||
bool powerOn = (status.mmPowerState == "on" &&
|
||||
status.mmState != "disabled" &&
|
||||
status.mmState != "failed");
|
||||
setBanner(powerOn ? "Disabling modem..." : "Enabling modem...");
|
||||
render();
|
||||
runCaptureCmd(powerOn ? "mmcli -m any -d >/dev/null 2>&1"
|
||||
: "mmcli -m any -e >/dev/null 2>&1");
|
||||
if (powerOn) {
|
||||
runCaptureCmd("mmcli -m any -d >/dev/null 2>&1");
|
||||
} else {
|
||||
runCaptureCmd(
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection boot >/dev/null 2>&1 "
|
||||
"|| mmcli -m any -e >/dev/null 2>&1");
|
||||
}
|
||||
refreshData(false);
|
||||
runAsyncCmd("sxmo_hook_statusbar.sh modem >/dev/null 2>&1");
|
||||
} else if (radioRowSel == 3) {
|
||||
@@ -1494,6 +1633,9 @@ int runModemApp(int argc, char** argv) {
|
||||
}
|
||||
};
|
||||
|
||||
int autoCheckStage = isPreload ? 0 : 2;
|
||||
int64_t nextAutoCheckMs = nowMs() + 2500;
|
||||
|
||||
if (!isPreload) {
|
||||
showWindow(openArg);
|
||||
}
|
||||
@@ -1841,6 +1983,28 @@ int runModemApp(int argc, char** argv) {
|
||||
timeoutMs = static_cast<int>(rRem);
|
||||
}
|
||||
}
|
||||
} else if (autoCheckStage < 2) {
|
||||
int64_t aRem = nextAutoCheckMs - now;
|
||||
if (aRem <= 0) {
|
||||
++autoCheckStage;
|
||||
nextAutoCheckMs = now + 4500;
|
||||
refreshData(false);
|
||||
if (status.slots[0].needsPin() || status.slots[0].needsPuk() ||
|
||||
status.slots[1].needsPin() || status.slots[1].needsPuk() ||
|
||||
status.mmState == "locked") {
|
||||
autoCheckStage = 2;
|
||||
showWindow("unlock");
|
||||
} else if ((status.slots[0].state == "present" ||
|
||||
status.slots[1].state == "present") &&
|
||||
(status.primaryGwSlot == 0 ||
|
||||
status.mmState == "disabled")) {
|
||||
runAsyncCmd(
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection boot >/dev/null "
|
||||
"2>&1");
|
||||
}
|
||||
} else if (timeoutMs < 0 || aRem < timeoutMs) {
|
||||
timeoutMs = static_cast<int>(aRem);
|
||||
}
|
||||
}
|
||||
|
||||
struct pollfd pfds[2];
|
||||
|
||||
@@ -183,7 +183,14 @@ inline bool sendPluginCommand(const char* name, const std::string& cmdLine) {
|
||||
return false;
|
||||
}
|
||||
std::string fifoPath = getPluginFifoPath(name);
|
||||
int fd = ::open(fifoPath.c_str(), O_WRONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
int fd = -1;
|
||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
fd = ::open(fifoPath.c_str(), O_WRONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
break;
|
||||
}
|
||||
::usleep(25000);
|
||||
}
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -1651,20 +1658,12 @@ inline std::string sendModemUssd(const std::string& input,
|
||||
if (clean.empty()) return "Empty USSD request.";
|
||||
|
||||
int rc = 0;
|
||||
std::string cmd;
|
||||
if (isReply && !isUssdCode(clean)) {
|
||||
cmd = "mmcli -m any --3gpp-ussd-respond=" + shellQuote(clean) + " 2>&1";
|
||||
} else {
|
||||
cmd = "mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1; "
|
||||
"mmcli -m any --3gpp-ussd-initiate=" + shellQuote(clean) + " 2>&1";
|
||||
}
|
||||
std::string mode = (isReply && !isUssdCode(clean)) ? "respond" : "initiate";
|
||||
std::string cmd =
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection ussd " + mode + " " +
|
||||
shellQuote(clean) + " 2>&1";
|
||||
|
||||
std::string out = trimStr(runCaptureCmd(cmd, &rc));
|
||||
size_t q1 = out.find('\'');
|
||||
size_t q2 = out.rfind('\'');
|
||||
if (q1 != std::string::npos && q2 != std::string::npos && q2 > q1) {
|
||||
out = out.substr(q1 + 1, q2 - q1 - 1);
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = (rc == 0) ? "USSD request completed." : "USSD request failed.";
|
||||
}
|
||||
@@ -1698,7 +1697,9 @@ inline std::string sendModemUssd(const std::string& input,
|
||||
}
|
||||
|
||||
inline void cancelModemUssd() {
|
||||
runAsyncCmd("mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1");
|
||||
runAsyncCmd(
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection ussd cancel >/dev/null 2>&1 "
|
||||
"|| mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1");
|
||||
}
|
||||
|
||||
} // namespace bananarchy
|
||||
|
||||
+107
-24
@@ -816,6 +816,97 @@ write_str_file(const char *path, const char *val)
|
||||
return n > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dunst_window_visible(void)
|
||||
{
|
||||
if (!dpy)
|
||||
return 0;
|
||||
Window r_ret, p_ret, *children = NULL;
|
||||
unsigned int nchildren = 0;
|
||||
int found = 0;
|
||||
if (!XQueryTree(dpy, root, &r_ret, &p_ret, &children, &nchildren) || !children)
|
||||
return 0;
|
||||
for (unsigned int i = 0; i < nchildren; i++) {
|
||||
XWindowAttributes wa;
|
||||
if (!XGetWindowAttributes(dpy, children[i], &wa) || wa.map_state != IsViewable)
|
||||
continue;
|
||||
XClassHint ch = { NULL, NULL };
|
||||
if (XGetClassHint(dpy, children[i], &ch)) {
|
||||
if ((ch.res_class && strcasecmp(ch.res_class, "Dunst") == 0) ||
|
||||
(ch.res_name && strcasecmp(ch.res_name, "dunst") == 0))
|
||||
found = 1;
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
if (ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(children);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_dunst_windows(void)
|
||||
{
|
||||
if (!dpy)
|
||||
return;
|
||||
Window r_ret, p_ret, *children = NULL;
|
||||
unsigned int nchildren = 0;
|
||||
int unmapped = 0;
|
||||
if (!XQueryTree(dpy, root, &r_ret, &p_ret, &children, &nchildren) || !children)
|
||||
return;
|
||||
for (unsigned int i = 0; i < nchildren; i++) {
|
||||
XClassHint ch = { NULL, NULL };
|
||||
if (XGetClassHint(dpy, children[i], &ch)) {
|
||||
if ((ch.res_class && strcasecmp(ch.res_class, "Dunst") == 0) ||
|
||||
(ch.res_name && strcasecmp(ch.res_name, "dunst") == 0)) {
|
||||
XUnmapWindow(dpy, children[i]);
|
||||
unmapped = 1;
|
||||
}
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
if (ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
}
|
||||
}
|
||||
XFree(children);
|
||||
if (unmapped)
|
||||
XFlush(dpy);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_all_notifications_now(void)
|
||||
{
|
||||
const char *ndir = getenv("SXMO_NOTIFDIR");
|
||||
char default_dir[256];
|
||||
if (!ndir || !ndir[0]) {
|
||||
const char *home = getenv("HOME");
|
||||
snprintf(default_dir, sizeof(default_dir), "%s/.local/share/sxmo/notifications",
|
||||
(home && home[0]) ? home : "/home/user");
|
||||
ndir = default_dir;
|
||||
}
|
||||
DIR *d = opendir(ndir);
|
||||
if (d) {
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(d)) != NULL) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
char fpath[512];
|
||||
snprintf(fpath, sizeof(fpath), "%s/%s", ndir, ent->d_name);
|
||||
unlink(fpath);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
unmap_dunst_windows();
|
||||
spawn_detached_sh(
|
||||
"dunstctl close-all >/dev/null 2>&1; "
|
||||
"dunstctl history-clear >/dev/null 2>&1; "
|
||||
"pkill -x dunstify >/dev/null 2>&1; "
|
||||
"sxmo_hook_statusbar.sh notifications >/dev/null 2>&1");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_builtin_toggle(const char *toggle_name)
|
||||
{
|
||||
@@ -914,27 +1005,7 @@ handle_builtin_toggle(const char *toggle_name)
|
||||
}
|
||||
spawn_detached_sh("sxmo_hook_statusbar.sh audio");
|
||||
} else if (strcmp(toggle_name, "notif_clear_all") == 0) {
|
||||
const char *ndir = getenv("SXMO_NOTIFDIR");
|
||||
char default_dir[256];
|
||||
if (!ndir || !ndir[0]) {
|
||||
const char *home = getenv("HOME");
|
||||
snprintf(default_dir, sizeof(default_dir), "%s/.local/share/sxmo/notifications",
|
||||
(home && home[0]) ? home : "/home/user");
|
||||
ndir = default_dir;
|
||||
}
|
||||
DIR *d = opendir(ndir);
|
||||
if (d) {
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(d)) != NULL) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
char fpath[512];
|
||||
snprintf(fpath, sizeof(fpath), "%s/%s", ndir, ent->d_name);
|
||||
unlink(fpath);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
spawn_detached_sh("sxmo_hook_statusbar.sh notifs");
|
||||
clear_all_notifications_now();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1102,10 @@ activate_selection(unsigned int ev_state)
|
||||
fclose(fp);
|
||||
}
|
||||
unlink(fpath);
|
||||
spawn_detached_sh("sxmo_hook_statusbar.sh notifs");
|
||||
unmap_dunst_windows();
|
||||
spawn_detached_sh(
|
||||
"dunstctl close-all >/dev/null 2>&1; "
|
||||
"sxmo_hook_statusbar.sh notifications >/dev/null 2>&1");
|
||||
hide_menu();
|
||||
menu_mode = MODE_NONE;
|
||||
if (action_cmd[0] && strcmp(action_cmd, "none") != 0)
|
||||
@@ -1040,6 +1114,11 @@ activate_selection(unsigned int ev_state)
|
||||
}
|
||||
if (strncmp(act, "@toggle:", 8) == 0) {
|
||||
handle_builtin_toggle(act + 8);
|
||||
if (strcmp(act + 8, "notif_clear_all") == 0) {
|
||||
hide_menu();
|
||||
menu_mode = MODE_NONE;
|
||||
return;
|
||||
}
|
||||
char cur_menu[64];
|
||||
snprintf(cur_menu, sizeof(cur_menu), "%s", current_builtin_menu);
|
||||
open_builtin_menu(cur_menu, cur_idx);
|
||||
@@ -1906,9 +1985,13 @@ open_builtin_menu(const char *menu_name, int keep_idx)
|
||||
reset_session_defaults(1, "Sys");
|
||||
append_active_call_entries();
|
||||
int nnotifs = count_notifications();
|
||||
int dunst_vis = dunst_window_visible();
|
||||
if (nnotifs > 0) {
|
||||
snprintf(label, sizeof(label), "%s Notifications (%d)", ICON_BEL, nnotifs);
|
||||
add_menu_item(label, "@menu:notifications", 1);
|
||||
} else if (dunst_vis) {
|
||||
snprintf(label, sizeof(label), "%s Clear Notification", ICON_BEL);
|
||||
add_menu_item(label, "@toggle:notif_clear_all", 0);
|
||||
}
|
||||
const char *sh = getenv("SHELL");
|
||||
if (!sh || !sh[0])
|
||||
@@ -2105,9 +2188,9 @@ open_builtin_menu(const char *menu_name, int keep_idx)
|
||||
add_menu_item(label, "@close", 0);
|
||||
} else if (strcmp(menu_name, "notifications") == 0) {
|
||||
reset_session_defaults(1, "Notifs");
|
||||
populate_notifications_menu();
|
||||
snprintf(label, sizeof(label), "%s Clear All Notifications", ICON_CLS);
|
||||
add_menu_item(label, "@toggle:notif_clear_all", 1);
|
||||
add_menu_item(label, "@toggle:notif_clear_all", 0);
|
||||
populate_notifications_menu();
|
||||
snprintf(label, sizeof(label), "%s System Menu", ICON_MNU);
|
||||
add_menu_item(label, "@menu:sys", 1);
|
||||
snprintf(label, sizeof(label), "%s Close Menu", ICON_CLS);
|
||||
|
||||
Reference in New Issue
Block a user