Add unified Xresources theme engine, Default.xth export, and xthemes manager plugin
This commit is contained in:
@@ -130,10 +130,12 @@ int runSmsApp(int argc, char** argv) {
|
||||
Visual* visual = DefaultVisual(dpy, screen);
|
||||
Colormap cmap = DefaultColormap(dpy, screen);
|
||||
|
||||
ThemeSpec initSpec = loadThemeSpec(dpy, screen);
|
||||
|
||||
XSetWindowAttributes swa {};
|
||||
swa.override_redirect = True;
|
||||
swa.background_pixel = 0x222222;
|
||||
swa.border_pixel = 0x005577;
|
||||
swa.background_pixel = initSpec.bgMain;
|
||||
swa.border_pixel = initSpec.selBg;
|
||||
swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
|
||||
VisibilityChangeMask | StructureNotifyMask;
|
||||
|
||||
@@ -155,37 +157,18 @@ int runSmsApp(int argc, char** argv) {
|
||||
GC gc = XCreateGC(dpy, pix, 0, nullptr);
|
||||
XftDraw* xftDraw = XftDrawCreate(dpy, pix, visual, cmap);
|
||||
|
||||
PangoFontMap* fontMap = pango_xft_get_font_map(dpy, screen);
|
||||
PangoContext* pangoCtx = pango_font_map_create_context(fontMap);
|
||||
|
||||
PangoLayout* layoutMain = pango_layout_new(pangoCtx);
|
||||
PangoFontDescription* descMain =
|
||||
pango_font_description_from_string("Fira Code, DejaVuSansM Nerd Font 15px");
|
||||
pango_layout_set_font_description(layoutMain, descMain);
|
||||
|
||||
PangoLayout* layoutSmall = pango_layout_new(pangoCtx);
|
||||
PangoFontDescription* descSmall =
|
||||
pango_font_description_from_string("Fira Code, DejaVuSansM Nerd Font 12px");
|
||||
pango_layout_set_font_description(layoutSmall, descSmall);
|
||||
|
||||
PangoLayout* layoutIcon = pango_layout_new(pangoCtx);
|
||||
PangoFontDescription* descIcon =
|
||||
pango_font_description_from_string("DejaVuSansM Nerd Font, Fira Code 16px");
|
||||
pango_layout_set_font_description(layoutIcon, descIcon);
|
||||
|
||||
auto allocColor = [&](const char* hex) {
|
||||
XftColor col {};
|
||||
XftColorAllocName(dpy, visual, cmap, hex, &col);
|
||||
return col;
|
||||
};
|
||||
|
||||
XftColor colWhite = allocColor("#ffffff");
|
||||
XftColor colLight = allocColor("#dddddd");
|
||||
XftColor colMuted = allocColor("#999999");
|
||||
XftColor colYellow = allocColor("#f4d03f");
|
||||
XftColor colGreen = allocColor("#2ecc71");
|
||||
XftColor colBlue = allocColor("#5dade2");
|
||||
XftColor colRed = allocColor("#e74c3c");
|
||||
PluginTheme pt;
|
||||
pt.init(dpy, screen, visual, cmap, win);
|
||||
auto& layoutMain = pt.layoutMain;
|
||||
auto& layoutSmall = pt.layoutSmall;
|
||||
auto& layoutIcon = pt.layoutIcon;
|
||||
auto& colWhite = pt.colWhite;
|
||||
auto& colLight = pt.colLight;
|
||||
auto& colMuted = pt.colMuted;
|
||||
auto& colYellow = pt.colYellow;
|
||||
auto& colGreen = pt.colGreen;
|
||||
auto& colBlue = pt.colBlue;
|
||||
auto& colRed = pt.colRed;
|
||||
|
||||
ContactBook book;
|
||||
std::vector<SmsThread> allThreads;
|
||||
@@ -442,9 +425,9 @@ int runSmsApp(int argc, char** argv) {
|
||||
const std::string& centerLabel,
|
||||
const std::string& rightLabel) {
|
||||
const int barY = kWinHeight - 26;
|
||||
XSetForeground(dpy, gc, 0x141414);
|
||||
XSetForeground(dpy, gc, pt.spec.bgFooter);
|
||||
XFillRectangle(dpy, pix, gc, 0, barY, kWinWidth, 26);
|
||||
XSetForeground(dpy, gc, 0x2d2d2d);
|
||||
XSetForeground(dpy, gc, pt.spec.divider);
|
||||
XDrawLine(dpy, pix, gc, 0, barY, kWinWidth, barY);
|
||||
|
||||
drawPango(layoutMain, &colBlue, 6, barY, 26, leftLabel);
|
||||
@@ -467,14 +450,15 @@ int runSmsApp(int argc, char** argv) {
|
||||
|
||||
auto drawUI = [&]() {
|
||||
if (!visible) return;
|
||||
pt.checkAndReload();
|
||||
|
||||
XSetForeground(dpy, gc, 0x222222);
|
||||
XSetForeground(dpy, gc, pt.spec.bgMain);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, kWinHeight);
|
||||
|
||||
if (mode == ViewMode::Threads) {
|
||||
XSetForeground(dpy, gc, 0x161616);
|
||||
XSetForeground(dpy, gc, pt.spec.bgHeader);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, 38);
|
||||
XSetForeground(dpy, gc, 0x333333);
|
||||
XSetForeground(dpy, gc, pt.spec.border);
|
||||
XDrawLine(dpy, pix, gc, 0, 37, kWinWidth, 37);
|
||||
|
||||
if (searchQuery.empty()) {
|
||||
@@ -521,12 +505,13 @@ int runSmsApp(int argc, char** argv) {
|
||||
bool isSel = (idx == selectedThread);
|
||||
|
||||
if (isSel) {
|
||||
XSetForeground(dpy, gc, 0x005577);
|
||||
XSetForeground(dpy, gc, pt.spec.selBg);
|
||||
XFillRectangle(dpy, pix, gc, 0, ry, kWinWidth, rowH - 1);
|
||||
XSetForeground(dpy, gc, 0x0088bb);
|
||||
XSetForeground(dpy, gc, pt.spec.accentAlt);
|
||||
XDrawLine(dpy, pix, gc, 0, ry, kWinWidth, ry);
|
||||
} else {
|
||||
XSetForeground(dpy, gc, (i % 2 == 0) ? 0x222222 : 0x1d1d1d);
|
||||
XSetForeground(dpy, gc,
|
||||
(i % 2 == 0) ? pt.spec.bgAltEven : pt.spec.bgAltOdd);
|
||||
XFillRectangle(dpy, pix, gc, 0, ry, kWinWidth, rowH - 1);
|
||||
}
|
||||
|
||||
@@ -562,9 +547,9 @@ int runSmsApp(int argc, char** argv) {
|
||||
searchQuery.empty() ? "Close" : "Clear");
|
||||
|
||||
} else if (mode == ViewMode::ThreadView) {
|
||||
XSetForeground(dpy, gc, 0x161616);
|
||||
XSetForeground(dpy, gc, pt.spec.bgHeader);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, 36);
|
||||
XSetForeground(dpy, gc, 0x333333);
|
||||
XSetForeground(dpy, gc, pt.spec.border);
|
||||
XDrawLine(dpy, pix, gc, 0, 35, kWinWidth, 35);
|
||||
|
||||
std::string cname = book.resolveName(activeNumber);
|
||||
@@ -640,13 +625,15 @@ int runSmsApp(int argc, char** argv) {
|
||||
int cardH = std::min(cg.h, areaH - 4);
|
||||
|
||||
unsigned long bg = isSel
|
||||
? 0x004466
|
||||
: (cg.incoming ? 0x262d32 : 0x1f2d38);
|
||||
? pt.spec.bgInputFocus
|
||||
: (cg.incoming ? pt.spec.bgBubbleIn
|
||||
: pt.spec.bgBubbleOut);
|
||||
XSetForeground(dpy, gc, bg);
|
||||
XFillRectangle(dpy, pix, gc, cardX, curY, cardW, cardH);
|
||||
|
||||
unsigned long accent = cg.incoming ? 0x2ecc71 : 0x5dade2;
|
||||
XSetForeground(dpy, gc, isSel ? 0xf4d03f : accent);
|
||||
unsigned long accent =
|
||||
cg.incoming ? pt.spec.success : pt.spec.info;
|
||||
XSetForeground(dpy, gc, isSel ? pt.spec.accent : accent);
|
||||
if (cg.incoming) {
|
||||
XFillRectangle(dpy, pix, gc, cardX, curY, 3, cardH);
|
||||
} else {
|
||||
@@ -672,9 +659,9 @@ int runSmsApp(int argc, char** argv) {
|
||||
drawSoftkeyBar("Options", "Reply", "Back");
|
||||
|
||||
} else if (mode == ViewMode::Compose) {
|
||||
XSetForeground(dpy, gc, 0x161616);
|
||||
XSetForeground(dpy, gc, pt.spec.bgHeader);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, 32);
|
||||
XSetForeground(dpy, gc, 0x333333);
|
||||
XSetForeground(dpy, gc, pt.spec.border);
|
||||
XDrawLine(dpy, pix, gc, 0, 31, kWinWidth, 31);
|
||||
|
||||
drawPango(layoutIcon, &colBlue, 6, 0, 30, kIconSend);
|
||||
@@ -703,9 +690,10 @@ int runSmsApp(int argc, char** argv) {
|
||||
|
||||
// Field 0: Recipient
|
||||
bool toSel = (composeField == 0);
|
||||
XSetForeground(dpy, gc, toSel ? 0x004466 : 0x1a1a1a);
|
||||
XSetForeground(dpy, gc,
|
||||
toSel ? pt.spec.bgInputFocus : pt.spec.bgInput);
|
||||
XFillRectangle(dpy, pix, gc, 6, 36, kWinWidth - 12, 32);
|
||||
XSetForeground(dpy, gc, toSel ? 0x0088bb : 0x383838);
|
||||
XSetForeground(dpy, gc, toSel ? pt.spec.accentAlt : pt.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 6, 36, kWinWidth - 13, 31);
|
||||
|
||||
std::string cname = book.resolveName(composeRecipient);
|
||||
@@ -719,9 +707,10 @@ int runSmsApp(int argc, char** argv) {
|
||||
|
||||
// Field 1: Message Body
|
||||
bool msgSel = (composeField == 1);
|
||||
XSetForeground(dpy, gc, msgSel ? 0x182630 : 0x181818);
|
||||
XSetForeground(dpy, gc,
|
||||
msgSel ? pt.spec.bgInputFocus : pt.spec.bgInput);
|
||||
XFillRectangle(dpy, pix, gc, 6, 72, kWinWidth - 12, 156);
|
||||
XSetForeground(dpy, gc, msgSel ? 0x0088bb : 0x383838);
|
||||
XSetForeground(dpy, gc, msgSel ? pt.spec.accentAlt : pt.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 6, 72, kWinWidth - 13, 155);
|
||||
|
||||
std::string bodyDisp = composeText;
|
||||
@@ -752,15 +741,15 @@ int runSmsApp(int argc, char** argv) {
|
||||
// Field 2 & 3: Send & Save Draft buttons
|
||||
bool sendSel = (composeField == 2);
|
||||
bool draftSel = (composeField == 3);
|
||||
XSetForeground(dpy, gc, sendSel ? 0x005577 : 0x262626);
|
||||
XSetForeground(dpy, gc, sendSel ? pt.spec.selBg : pt.spec.bgButton);
|
||||
XFillRectangle(dpy, pix, gc, 6, 234, 118, 30);
|
||||
XSetForeground(dpy, gc, sendSel ? 0x0088bb : 0x444444);
|
||||
XSetForeground(dpy, gc, sendSel ? pt.spec.accentAlt : pt.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 6, 234, 117, 29);
|
||||
drawPango(layoutMain, &colGreen, 18, 234, 30, "Send SMS", 100);
|
||||
|
||||
XSetForeground(dpy, gc, draftSel ? 0x005577 : 0x262626);
|
||||
XSetForeground(dpy, gc, draftSel ? pt.spec.selBg : pt.spec.bgButton);
|
||||
XFillRectangle(dpy, pix, gc, 130, 234, 104, 30);
|
||||
XSetForeground(dpy, gc, draftSel ? 0x0088bb : 0x444444);
|
||||
XSetForeground(dpy, gc, draftSel ? pt.spec.accentAlt : pt.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 130, 234, 103, 29);
|
||||
drawPango(layoutMain, &colYellow, 146, 234, 30, "Draft", 84);
|
||||
|
||||
@@ -778,7 +767,7 @@ int runSmsApp(int argc, char** argv) {
|
||||
}
|
||||
|
||||
} else if (mode == ViewMode::PickContact) {
|
||||
XSetForeground(dpy, gc, 0x161616);
|
||||
XSetForeground(dpy, gc, pt.spec.bgHeader);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, 34);
|
||||
drawPango(layoutIcon, &colBlue, 8, 0, 34, kIconBook);
|
||||
drawPango(layoutMain, &colWhite, 30, 0, 34, "Select Recipient", 200);
|
||||
@@ -799,7 +788,7 @@ int runSmsApp(int argc, char** argv) {
|
||||
const auto& c = pickerContacts[idx];
|
||||
int ry = listY + i * rowH;
|
||||
bool isSel = (idx == selectedPicker);
|
||||
XSetForeground(dpy, gc, isSel ? 0x005577 : 0x222222);
|
||||
XSetForeground(dpy, gc, isSel ? pt.spec.selBg : pt.spec.bgMain);
|
||||
XFillRectangle(dpy, pix, gc, 0, ry, kWinWidth, rowH - 1);
|
||||
drawPango(layoutIcon, c.isRecent ? &colYellow : &colBlue, 6, ry + 1,
|
||||
20, c.isRecent ? kIconClock : kIconUser);
|
||||
@@ -811,7 +800,7 @@ int runSmsApp(int argc, char** argv) {
|
||||
drawSoftkeyBar("Select", "Select", "Back");
|
||||
|
||||
} else if (mode == ViewMode::Options) {
|
||||
XSetForeground(dpy, gc, 0x161616);
|
||||
XSetForeground(dpy, gc, pt.spec.bgHeader);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, 34);
|
||||
drawPango(layoutIcon, &colBlue, 8, 0, 34, kIconList);
|
||||
drawPango(layoutMain, &colWhite, 30, 0, 34, "Message Options", 200);
|
||||
@@ -821,7 +810,7 @@ int runSmsApp(int argc, char** argv) {
|
||||
for (size_t i = 0; i < optionsList.size(); ++i) {
|
||||
int ry = listY + static_cast<int>(i) * rowH;
|
||||
bool isSel = (static_cast<int>(i) == selectedOption);
|
||||
XSetForeground(dpy, gc, isSel ? 0x005577 : 0x222222);
|
||||
XSetForeground(dpy, gc, isSel ? pt.spec.selBg : pt.spec.bgMain);
|
||||
XFillRectangle(dpy, pix, gc, 0, ry, kWinWidth, rowH - 1);
|
||||
drawPango(layoutIcon, isSel ? &colYellow : &colBlue, 10, ry, rowH,
|
||||
optionsList[i].icon);
|
||||
@@ -831,7 +820,7 @@ int runSmsApp(int argc, char** argv) {
|
||||
drawSoftkeyBar("Select", "Select", "Back");
|
||||
|
||||
} else if (mode == ViewMode::ConfirmDelete) {
|
||||
XSetForeground(dpy, gc, 0x161616);
|
||||
XSetForeground(dpy, gc, pt.spec.bgHeader);
|
||||
XFillRectangle(dpy, pix, gc, 0, 0, kWinWidth, 36);
|
||||
drawPango(layoutIcon, &colRed, 8, 0, 36, kIconTrash);
|
||||
drawPango(layoutMain, &colWhite, 30, 0, 36, "Delete Thread?", 200);
|
||||
@@ -844,7 +833,10 @@ int runSmsApp(int argc, char** argv) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int ry = 164 + i * 40;
|
||||
bool isSel = (confirmSelected == i);
|
||||
XSetForeground(dpy, gc, isSel ? (i == 1 ? 0x922b21 : 0x005577) : 0x2a2a2a);
|
||||
XSetForeground(
|
||||
dpy, gc,
|
||||
isSel ? (i == 1 ? pt.spec.dangerBg : pt.spec.selBg)
|
||||
: pt.spec.bgButton);
|
||||
XFillRectangle(dpy, pix, gc, 16, ry, kWinWidth - 32, 34);
|
||||
drawPango(layoutMain, &colWhite, 28, ry, 34,
|
||||
i == 0 ? "No, Keep Thread" : "Yes, Delete Thread", 184);
|
||||
@@ -856,9 +848,9 @@ int runSmsApp(int argc, char** argv) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(sendMutex);
|
||||
if (!statusBanner.empty() && tNow < statusBannerUntilMs) {
|
||||
XSetForeground(dpy, gc, 0x102535);
|
||||
XSetForeground(dpy, gc, pt.spec.bgToast);
|
||||
XFillRectangle(dpy, pix, gc, 8, kWinHeight - 58, kWinWidth - 16, 28);
|
||||
XSetForeground(dpy, gc, 0x5dade2);
|
||||
XSetForeground(dpy, gc, pt.spec.info);
|
||||
XDrawRectangle(dpy, pix, gc, 8, kWinHeight - 58, kWinWidth - 17, 27);
|
||||
drawPango(layoutSmall, &colWhite, 14, kWinHeight - 58, 28, statusBanner,
|
||||
kWinWidth - 28);
|
||||
@@ -1106,6 +1098,9 @@ int runSmsApp(int argc, char** argv) {
|
||||
for (const auto& cmd : readFifoLines(fifoFd)) {
|
||||
if (cmd == "NOP") {
|
||||
continue;
|
||||
} else if (cmd == "RELOAD_THEME") {
|
||||
pt.reload();
|
||||
if (visible) drawUI();
|
||||
} else if (cmd == "CLOSE") {
|
||||
hideWindow();
|
||||
} else if (cmd == "OPEN") {
|
||||
@@ -1416,7 +1411,10 @@ int runSmsApp(int argc, char** argv) {
|
||||
if (pr > 0) {
|
||||
if (fifoIdx >= 0 && (pfds[fifoIdx].revents & POLLIN)) {
|
||||
for (const auto& cmd : readFifoLines(fifoFd)) {
|
||||
if (cmd == "CLOSE") {
|
||||
if (cmd == "RELOAD_THEME") {
|
||||
pt.reload();
|
||||
if (visible) drawUI();
|
||||
} else if (cmd == "CLOSE") {
|
||||
hideWindow();
|
||||
} else if (cmd == "OPEN") {
|
||||
showWindow("");
|
||||
|
||||
Reference in New Issue
Block a user