ultimatepp/uppsrc/CtrlLib/ChX11.cpp

179 lines
4 KiB
C++

#include "CtrlLib.h"
#ifdef GUI_X11
namespace Upp {
#define LLOG(x)
VectorMap<String, Value> GetXSettings()
{
VectorMap<String, Value> map;
Window owner = XGetSelectionOwner(Xdisplay, XAtom("_XSETTINGS_S0"));
if(owner == None) {
LLOG("No XSettings manager found for screen " << screen);
return map;
}
Atom settings_atom = XAtom("_XSETTINGS_SETTINGS");
String data = GetProperty(owner, settings_atom, settings_atom);
if(data.IsEmpty()) {
LLOG("Failed to read XSettings property or property is empty.");
return map;
}
const char *ptr = data.Begin();
const char *lim = data.End();
if(data.GetCount() < 12)
return map;
byte be = ptr[0];
auto Peek32 = [&](const char *p) {
return be ? Peek32be(p) : Peek32le(p);
};
auto Peek16 = [&](const char *p) {
return be ? Peek16be(p) : Peek16le(p);
};
int n_settings = Peek32(ptr + 8);
ptr += 12;
for(int i = 0; i < n_settings && ptr < lim; i++) {
if(lim - ptr < 4)
break;
byte type = *ptr++; // 0 = Integer, 1 = String, 2 = Color
ptr++; // unused
int name_len = Peek16(ptr);
ptr += 2;
if(lim - ptr < name_len)
break;
String name(ptr, name_len);
ptr += (name_len + 3) & ~3;
ptr += 4; // Last-change serial
if(type == 0) { // Integer
if(lim - ptr < 4)
break;
map.GetAdd(name) = (int)Peek32(ptr);
ptr += 4;
}
else
if(type == 1) { // String
if(lim - ptr < 4)
break;
int str_len = Peek32(ptr);
ptr += 4;
if(lim - ptr < str_len)
break;
map.GetAdd(name) = String(ptr, str_len);
ptr += (str_len + 3) & ~3; // Align to 4 bytes
}
else
if(type == 2) { // Color - ignored
if(lim - ptr < 8)
break;
ptr += 8;
}
}
return map;
}
void ChHostSkin()
{
VectorMap<String, Value> map = GetXSettings();
try {
String font_name = map.Get("Gtk/FontName", "");
String theme = map.Get("Net/ThemeName", "");
//int scaling = map.Get("Gdk/WindowScalingFactor", 1);
int xdpi = map.Get("Xft/DPI", 98347);
int fontface = Font::ARIAL;
int fontheight = 13;
bool bold = false;
bool italic = false;
const char *q = strrchr(font_name, ' ');
if(q) {
int h = atoi(q);
if(h)
fontheight = h;
String face(font_name, q);
fontface = Font::FindFaceNameIndex(face);
if(fontface == 0) {
for(;;) {
const char *q = strrchr(face, ' ');
if(!q) break;
const char *s = q + 1;
if(stricmp(s, "Bold") == 0 || stricmp(s, "Heavy") == 0)
bold = true;
else
if(stricmp(s, "Italic") == 0 || stricmp(s, "Oblique") == 0)
italic = true;
else
if(stricmp(s, "Regular") == 0 || stricmp(s, "Light") || stricmp(s, "Medium"))
;
else
continue;
face = String(~face, q);
}
fontface = Font::FindFaceNameIndex(face);
if(fontface == 0) {
if(ToUpper(face[0]) == 'M')
fontface = Font::COURIER;
else
if(ToUpper(face[0]) == 'S' && ToUpper(face[1]) == 'e')
fontface = Font::ROMAN;
else
fontface = Font::ARIAL;
}
}
}
Font gui_font = Font(fontface, fround(fontheight * xdpi / (72*1024.0))).Bold(bold).Italic(italic);
Font::SetDefaultFont(gui_font);
SColorFace_Write(Color(242, 241, 240));
SColorMenu_Write(Color(242, 241, 240));
SColorHighlight_Write(Color(50, 50, 250));
auto ThemeHasWord = [&](const char *text) {
int q = ToLower(theme).Find(text);
if(q >= 0) {
if(q > 0) {
int pc = theme[q - 1];
if(!(IsUpper(theme[q]) && IsLower(pc) || !IsLetter(pc)))
return false;
}
int l = strlen(text);
int nc = theme[q + l];
if(!(IsLower(text[l - 1]) && IsUpper(nc) || !IsLetter(nc)))
return false;
return true;
}
return false;
};
if(ThemeHasWord("dark") || ThemeHasWord("inverse") || ThemeHasWord("black"))
ChDarkSkin();
else
ChStdSkin();
}
catch(ValueTypeError) {}
SwapOKCancel_Write(Environment().Get("KDE_FULL_SESSION", String()) != "true");
}
};
#endif