Browse Source

X11: Add XSettings class for parsing and storing display settings according to the XSETTINGS specification

v6.1.6
ed 4 years ago
parent
commit
f69de31094
2 changed files with 213 additions and 0 deletions
  1. +142
    -0
      modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp
  2. +71
    -0
      modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h

+ 142
- 0
modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp View File

@@ -178,6 +178,148 @@ XWindowSystemUtilities::GetXProperty::~GetXProperty()
X11Symbols::getInstance()->xFree (data);
}
//==============================================================================
XWindowSystemUtilities::XSettings::XSettings (::Display* d)
: display (d)
{
settingsAtom = Atoms::getCreating (display, "_XSETTINGS_SETTINGS");
settingsWindow = X11Symbols::getInstance()->xGetSelectionOwner (display,
Atoms::getCreating (display, "_XSETTINGS_S0"));
jassert (settingsWindow != None);
update();
}
XWindowSystemUtilities::XSetting XWindowSystemUtilities::XSettings::getSetting (const String& name) const
{
const auto iter = settings.find (name);
if (iter != settings.end())
return iter->second;
return {};
}
void XWindowSystemUtilities::XSettings::update()
{
const GetXProperty prop { display,
settingsWindow,
settingsAtom,
0L,
std::numeric_limits<long>::max(),
false,
settingsAtom };
if (prop.success
&& prop.actualType == settingsAtom
&& prop.actualFormat == 8
&& prop.numItems > 0)
{
const auto bytes = (size_t) prop.numItems;
auto* data = prop.data;
size_t byteNum = 0;
const auto increment = [&] (size_t amount)
{
data += amount;
byteNum += amount;
};
struct Header
{
CARD8 byteOrder;
CARD8 padding[3];
CARD32 serial;
CARD32 nSettings;
};
const auto* header = reinterpret_cast<const Header*> (data);
const auto headerSerial = (int) header->serial;
increment (sizeof (Header));
const auto readCARD16 = [&]() -> CARD16
{
if (byteNum + sizeof (CARD16) > bytes)
return {};
const auto value = header->byteOrder == MSBFirst ? ByteOrder::bigEndianShort (data)
: ByteOrder::littleEndianShort (data);
increment (sizeof (CARD16));
return value;
};
const auto readCARD32 = [&]() -> CARD32
{
if (byteNum + sizeof (CARD32) > bytes)
return {};
const auto value = header->byteOrder == MSBFirst ? ByteOrder::bigEndianInt (data)
: ByteOrder::littleEndianInt (data);
increment (sizeof (CARD32));
return value;
};
const auto readString = [&] (size_t nameLen) -> String
{
const auto padded = (nameLen + 3) & (~(size_t) 3);
if (byteNum + padded > bytes)
return {};
auto* ptr = reinterpret_cast<const char*> (data);
const String result (ptr, nameLen);
increment (padded);
return result;
};
CARD16 setting = 0;
while (byteNum < bytes && setting < header->nSettings)
{
const auto type = *reinterpret_cast<const char*> (data);
increment (2);
const auto name = readString (readCARD16());
const auto serial = (int) readCARD32();
enum { XSettingsTypeInteger, XSettingsTypeString, XSettingsTypeColor };
const auto parsedSetting = [&]() -> XSetting
{
switch (type)
{
case XSettingsTypeInteger:
return { name, (int) readCARD32() };
case XSettingsTypeString:
return { name, readString (readCARD32()) };
case XSettingsTypeColor:
// Order is important, these should be kept as separate statements!
const auto r = (uint8) readCARD16();
const auto g = (uint8) readCARD16();
const auto b = (uint8) readCARD16();
const auto a = (uint8) readCARD16();
return { name, Colour { r, g, b, a } };
}
return {};
}();
if (serial > lastUpdateSerial)
{
settings[parsedSetting.name] = parsedSetting;
listeners.call ([&parsedSetting] (Listener& l) { l.settingChanged (parsedSetting); });
}
setting += 1;
}
lastUpdateSerial = headerSerial;
}
}
//==============================================================================
::Window juce_messageWindowHandle;
XContext windowHandleXContext;


+ 71
- 0
modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h View File

@@ -90,6 +90,77 @@ namespace XWindowSystemUtilities
XdndTypeList, XdndActionList, XdndActionDescription, XdndActionCopy, XdndActionPrivate,
XembedMsgType, XembedInfo, allowedActions[5], allowedMimeTypes[4], utf8String, clipboard, targets;
};
//==============================================================================
/** Represents a setting according to the XSETTINGS specification.
@tags{GUI}
*/
struct XSetting
{
enum class Type
{
integer,
string,
colour,
invalid
};
XSetting() = default;
XSetting (const String& n, int v) : name (n), type (Type::integer), integerValue (v) {}
XSetting (const String& n, const String& v) : name (n), type (Type::string), stringValue (v) {}
XSetting (const String& n, const Colour& v) : name (n), type (Type::colour), colourValue (v) {}
bool isValid() const noexcept { return type != Type::invalid; }
String name;
Type type = Type::invalid;
int integerValue = -1;
String stringValue;
Colour colourValue;
};
/** Parses and stores the X11 settings for a display according to the XSETTINGS
specification.
@tags{GUI}
*/
class XSettings
{
public:
explicit XSettings (::Display*);
//==============================================================================
void update();
::Window getSettingsWindow() const noexcept { return settingsWindow; }
XSetting getSetting (const String& settingName) const;
//==============================================================================
struct Listener
{
virtual ~Listener() = default;
virtual void settingChanged (const XSetting& settingThatHasChanged) = 0;
};
void addListener (Listener* listenerToAdd) { listeners.add (listenerToAdd); }
void removeListener (Listener* listenerToRemove) { listeners.remove (listenerToRemove); }
private:
::Display* display = nullptr;
::Window settingsWindow = None;
Atom settingsAtom;
int lastUpdateSerial = -1;
std::unordered_map<String, XSetting> settings;
ListenerList<Listener> listeners;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XSettings)
};
}
//==============================================================================


Loading…
Cancel
Save