Add ringtones/wallpapers plugins, AT console, dialer USSD/*#06#, and SIM icon fix

This commit is contained in:
Luxferre
2026-10-24 19:58:11 +03:00
parent e549aaf413
commit dc59704547
64 changed files with 2743 additions and 130 deletions
+288 -19
View File
@@ -152,6 +152,19 @@ int dialer_run_main(int argc, char** argv) {
bool zeroHeld = false;
int64_t zeroPressMs = 0;
enum class DialerModal {
Inactive = 0,
Imei = 1,
Ussd = 2,
};
DialerModal modal = DialerModal::Inactive;
DeviceImeis deviceImeis;
std::string ussdCode;
std::string ussdResponse;
std::string ussdReplyInput;
bool ussdSessionActive = false;
int ussdScrollLine = 0;
auto updateFilter = [&]() {
filtered.clear();
if (number.empty()) {
@@ -256,15 +269,23 @@ int dialer_run_main(int argc, char** argv) {
subText = "Dial: " + c.number;
subCol = &colYellow;
} else if (!number.empty()) {
std::string exactName = book.resolveName(number);
if (!exactName.empty()) {
subText = exactName;
subCol = &colGreen;
} else if (!filtered.empty()) {
subText = filtered[0].name + " (" + filtered[0].number + ")";
subCol = &colBlue;
if (number == "*#06#") {
subText = "Show Device IMEI (1 & 2)";
subCol = &colYellow;
} else if (isUssdCode(number)) {
subText = "USSD Code (Press Call/OK to send)";
subCol = &colYellow;
} else {
subText = "Press Call to dial (Hold 0: +)";
std::string exactName = book.resolveName(number);
if (!exactName.empty()) {
subText = exactName;
subCol = &colGreen;
} else if (!filtered.empty()) {
subText = filtered[0].name + " (" + filtered[0].number + ")";
subCol = &colBlue;
} else {
subText = "Press Call to dial (Hold 0: +)";
}
}
} else {
subText = "0-9/*/# Dial | Hold 0: +";
@@ -339,9 +360,111 @@ int dialer_run_main(int argc, char** argv) {
XFillRectangle(dpy, pix, gc, 0, sbY, kWinWidth, 1);
std::string leftLabel = number.empty() ? "Call Log" : "+Sign";
std::string centerLabel = "CALL";
std::string centerLabel =
(selected < 0 && isUssdCode(number)) ? "SEND" : "CALL";
std::string rightLabel = number.empty() ? "Close" : "Clear";
if (modal == DialerModal::Imei) {
XSetForeground(dpy, gc, theme.spec.bgOverlay);
XFillRectangle(dpy, pix, gc, 10, 22, kWinWidth - 20, kWinHeight - kSoftbarH - 34);
XSetForeground(dpy, gc, theme.spec.accent);
XDrawRectangle(dpy, pix, gc, 10, 22, kWinWidth - 21, kWinHeight - kSoftbarH - 35);
drawPango(layoutIcon, &colYellow, 18, 28, 24, kIconInfo);
drawPango(layoutMain, &colYellow, 38, 28, 24, "Device IMEI (*#06#)", 184);
XSetForeground(dpy, gc, theme.spec.divider);
XFillRectangle(dpy, pix, gc, 16, 54, kWinWidth - 32, 1);
// Slot 1 IMEI card
XSetForeground(dpy, gc, theme.spec.bgAltEven);
XFillRectangle(dpy, pix, gc, 16, 62, kWinWidth - 32, 54);
XSetForeground(dpy, gc, theme.spec.border);
XDrawRectangle(dpy, pix, gc, 16, 62, kWinWidth - 33, 53);
drawPango(layoutSmall, &colBlue, 22, 65, 18, "IMEI 1 (SIM Slot 1):");
drawPango(layoutMain, &colWhite, 22, 85, 24,
deviceImeis.imei1.empty() ? "Unavailable" : deviceImeis.imei1,
kWinWidth - 44);
// Slot 2 IMEI card
XSetForeground(dpy, gc, theme.spec.bgAltEven);
XFillRectangle(dpy, pix, gc, 16, 124, kWinWidth - 32, 54);
XSetForeground(dpy, gc, theme.spec.border);
XDrawRectangle(dpy, pix, gc, 16, 124, kWinWidth - 33, 53);
drawPango(layoutSmall, &colGreen, 22, 127, 18, "IMEI 2 (SIM Slot 2):");
drawPango(layoutMain, &colWhite, 22, 147, 24,
deviceImeis.imei2.empty() ? "Unavailable" : deviceImeis.imei2,
kWinWidth - 44);
std::string svLine = "IMEI SV: " +
(deviceImeis.imeiSv.empty() ? "--" : deviceImeis.imeiSv);
drawPango(layoutSmall, &colMuted, 22, 188, 20, svLine, kWinWidth - 44);
leftLabel = "";
centerLabel = "OK";
rightLabel = "Close";
} else if (modal == DialerModal::Ussd) {
XSetForeground(dpy, gc, theme.spec.bgOverlay);
XFillRectangle(dpy, pix, gc, 8, 14, kWinWidth - 16, kWinHeight - kSoftbarH - 22);
XSetForeground(dpy, gc, theme.spec.accent);
XDrawRectangle(dpy, pix, gc, 8, 14, kWinWidth - 17, kWinHeight - kSoftbarH - 23);
std::string hdr = "USSD (" + ussdCode + ")";
drawPango(layoutMain, &colYellow, 16, 18, 22, hdr, kWinWidth - 32);
// Response area
XSetForeground(dpy, gc, theme.spec.bgAltEven);
XFillRectangle(dpy, pix, gc, 14, 42, kWinWidth - 28, 152);
XSetForeground(dpy, gc, theme.spec.border);
XDrawRectangle(dpy, pix, gc, 14, 42, kWinWidth - 29, 151);
pango_layout_set_width(layoutSmall, (kWinWidth - 40) * PANGO_SCALE);
pango_layout_set_wrap(layoutSmall, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layoutSmall, PANGO_ELLIPSIZE_NONE);
pango_layout_set_text(layoutSmall, ussdResponse.c_str(),
static_cast<int>(ussdResponse.size()));
int lineCount = pango_layout_get_line_count(layoutSmall);
int maxVisLines = 7;
if (ussdScrollLine > std::max(0, lineCount - maxVisLines)) {
ussdScrollLine = std::max(0, lineCount - maxVisLines);
}
int curY = 46;
for (int li = ussdScrollLine;
li < lineCount && (li - ussdScrollLine) < maxVisLines; ++li) {
PangoLayoutLine* pl = pango_layout_get_line_readonly(layoutSmall, li);
if (pl) {
PangoRectangle ink{}, logical{};
pango_layout_line_get_pixel_extents(pl, &ink, &logical);
pango_xft_render_layout_line(
xftDraw, &colWhite, pl, 20 * PANGO_SCALE,
(curY - logical.y) * PANGO_SCALE);
curY += std::max(18, logical.height + 2);
}
}
pango_layout_set_width(layoutSmall, -1);
// Reply / Follow-up USSD input box
drawPango(layoutSmall, ussdSessionActive ? &colGreen : &colMuted,
16, 198, 18,
ussdSessionActive ? "Session active - Reply:" : "Reply or dial USSD:");
XSetForeground(dpy, gc, theme.spec.bgInputFocus);
XFillRectangle(dpy, pix, gc, 14, 216, kWinWidth - 28, 26);
XSetForeground(dpy, gc, theme.spec.selBg);
XDrawRectangle(dpy, pix, gc, 14, 216, kWinWidth - 29, 25);
drawPango(layoutMain, &colWhite, 20, 216, 26, ussdReplyInput + "_",
kWinWidth - 40);
if (!ussdReplyInput.empty() || ussdSessionActive) {
leftLabel = "Send";
centerLabel = "SEND";
rightLabel = "Close";
} else {
leftLabel = "Retry";
centerLabel = "OK";
rightLabel = "Close";
}
}
drawPango(layoutMain, &colLight, 6, sbY + 1, kSoftbarH - 1, leftLabel);
int cw = pangoWidth(layoutMain, centerLabel);
drawPango(layoutMain, &colGreen, (kWinWidth - cw) / 2, sbY + 1,
@@ -367,8 +490,31 @@ int dialer_run_main(int argc, char** argv) {
render();
XSync(dpy, False);
auto openImeiModal = [&]() {
deviceImeis = queryDeviceImeis();
modal = DialerModal::Imei;
number.clear();
selected = allContacts.empty() ? -1 : 0;
updateFilter();
render();
};
auto executeUssd = [&](const std::string& codeOrReply, bool isReply) {
modal = DialerModal::Ussd;
if (!isReply || isUssdCode(codeOrReply)) {
ussdCode = codeOrReply;
}
ussdScrollLine = 0;
ussdResponse = "Sending USSD " + codeOrReply + "...";
ussdReplyInput.clear();
render();
ussdResponse = sendModemUssd(codeOrReply, isReply, &ussdSessionActive);
render();
};
auto showWindow = [&](const std::string& arg) {
closeOtherPlugins("dialer");
modal = DialerModal::Inactive;
bool themeChanged = theme.checkAndReload(
dpy, screen, visual, cmap, layoutMain, layoutSmall, layoutIcon,
layoutNum, win);
@@ -394,7 +540,9 @@ int dialer_run_main(int argc, char** argv) {
usleep(2000);
}
bool reloaded = reloadContactsIfNeeded();
if (!cleanArg.empty() || reloaded || themeChanged || number != cleanArg) {
if (cleanArg == "*#06#") {
openImeiModal();
} else if (!cleanArg.empty() || reloaded || themeChanged || number != cleanArg) {
number = cleanArg;
selected = number.empty() ? (allContacts.empty() ? -1 : 0) : -1;
updateFilter();
@@ -408,8 +556,12 @@ int dialer_run_main(int argc, char** argv) {
}
number += cleanArg;
selected = -1;
updateFilter();
render();
if (number == "*#06#") {
openImeiModal();
} else {
updateFilter();
render();
}
}
};
@@ -440,7 +592,13 @@ int dialer_run_main(int argc, char** argv) {
softkeyPending = 0;
softkeyDeadlineMs = 0;
zeroHeld = false;
if (!number.empty() || selected != (allContacts.empty() ? -1 : 0)) {
if (modal == DialerModal::Ussd && ussdSessionActive) {
cancelModemUssd();
ussdSessionActive = false;
}
if (modal != DialerModal::Inactive || !number.empty() ||
selected != (allContacts.empty() ? -1 : 0)) {
modal = DialerModal::Inactive;
number.clear();
selected = allContacts.empty() ? -1 : 0;
updateFilter();
@@ -557,6 +715,79 @@ int dialer_run_main(int argc, char** argv) {
}
char dialCh = mapDialKey(sym, ev.xkey.keycode, ev.xkey.state);
if (modal == DialerModal::Imei) {
if (sym == XK_Return || sym == XK_KP_Enter || sym == XK_Escape ||
sym == XK_BackSpace || sym == XF86XK_Phone ||
sym == XF86XK_PickupPhone) {
modal = DialerModal::Inactive;
render();
}
continue;
}
if (modal == DialerModal::Ussd) {
if (dialCh != '\0') {
if (ussdReplyInput.size() < 32) {
ussdReplyInput.push_back(dialCh);
render();
}
continue;
}
if (sym == XK_BackSpace || sym == XK_Left || sym == XK_KP_Left) {
if (!ussdReplyInput.empty()) {
ussdReplyInput.pop_back();
render();
} else if (sym == XK_BackSpace) {
if (ussdSessionActive) {
cancelModemUssd();
ussdSessionActive = false;
}
modal = DialerModal::Inactive;
render();
}
continue;
}
if (sym == XK_Escape) {
if (ussdSessionActive) {
cancelModemUssd();
ussdSessionActive = false;
}
modal = DialerModal::Inactive;
render();
continue;
}
if (sym == XK_Up || sym == XK_KP_Up) {
if (ussdScrollLine > 0) {
--ussdScrollLine;
render();
}
continue;
}
if (sym == XK_Down || sym == XK_KP_Down) {
++ussdScrollLine;
render();
continue;
}
if (sym == XK_Return || sym == XK_KP_Enter ||
sym == XF86XK_Phone || sym == XF86XK_PickupPhone ||
sym == XF86XK_Send) {
if (!ussdReplyInput.empty()) {
if (ussdReplyInput == "*#06#") {
openImeiModal();
} else {
std::string req = ussdReplyInput;
executeUssd(req, !isUssdCode(req));
}
} else if (!ussdSessionActive) {
modal = DialerModal::Inactive;
render();
}
continue;
}
continue;
}
if (dialCh != '\0') {
if (nowMs() - openStartMs < 40 && number.size() == 1 &&
number[0] == dialCh) {
@@ -570,6 +801,10 @@ int dialer_run_main(int argc, char** argv) {
} else {
zeroHeld = false;
}
if (number == "*#06#") {
openImeiModal();
continue;
}
updateFilter();
render();
continue;
@@ -632,12 +867,22 @@ int dialer_run_main(int argc, char** argv) {
case XK_Return:
case XK_KP_Enter:
case XF86XK_Phone:
case XF86XK_PickupPhone: {
case XF86XK_PickupPhone:
case XF86XK_Send: {
std::string target = selectActiveNumber();
if (!target.empty()) {
writeSoftkeySuppress(nowMs() + 350);
hideWindow(true);
placePhoneCall(target);
if (target == "*#06#") {
openImeiModal();
} else if (isUssdCode(target)) {
number.clear();
selected = allContacts.empty() ? -1 : 0;
updateFilter();
executeUssd(target, false);
} else {
writeSoftkeySuppress(nowMs() + 350);
hideWindow(true);
placePhoneCall(target);
}
}
break;
}
@@ -658,7 +903,21 @@ int dialer_run_main(int argc, char** argv) {
runAsyncArgv("xdrawer");
}
} else if (comb == 1) {
if (number.empty()) {
if (modal == DialerModal::Imei) {
modal = DialerModal::Inactive;
render();
} else if (modal == DialerModal::Ussd) {
if (!ussdReplyInput.empty()) {
if (ussdReplyInput == "*#06#") {
openImeiModal();
} else {
std::string req = ussdReplyInput;
executeUssd(req, !isUssdCode(req));
}
} else if (!ussdCode.empty()) {
executeUssd(ussdCode, false);
}
} else if (number.empty()) {
writeSoftkeySuppress(nowMs() + 250);
hideWindow(false);
if (!sendPluginCommand("calllog", "OPEN")) {
@@ -675,7 +934,17 @@ int dialer_run_main(int argc, char** argv) {
render();
}
} else if (comb == 2) {
if (!number.empty()) {
if (modal == DialerModal::Imei) {
modal = DialerModal::Inactive;
render();
} else if (modal == DialerModal::Ussd) {
if (ussdSessionActive) {
cancelModemUssd();
ussdSessionActive = false;
}
modal = DialerModal::Inactive;
render();
} else if (!number.empty()) {
number.pop_back();
selected = -1;
updateFilter();