diff --git a/evoke/EvokeService.cpp b/evoke/EvokeService.cpp index b4476d7..033ac8f 100644 --- a/evoke/EvokeService.cpp +++ b/evoke/EvokeService.cpp @@ -454,6 +454,16 @@ do_it: edelib::alert(_("Unable to load XSETTINGS manager properly")); stop_xsettings_manager(); } + + if(!xsm) return; + + /* testing code + * FIXME: move this to outside client + */ + xsm->set_int("Net/DoubleClickTime", 234); + xsm->set_color("Net/Background/Normal", 34, 45, 23, 0); + xsm->set_string("Net/UserName", "John Foo"); + xsm->notify(); } void EvokeService::stop_xsettings_manager(void) { diff --git a/evoke/Xsm.cpp b/evoke/Xsm.cpp index 9835c84..bae9476 100644 --- a/evoke/Xsm.cpp +++ b/evoke/Xsm.cpp @@ -11,17 +11,36 @@ */ #include "Xsm.h" + #include +#include + #include -#include // snprintf +#include // CARD16, CARD32 + +#include // snprintf +#include // free +#include // strdup, strcmp + +#define XSETTINGS_PAD(n, p) ((n + p - 1) & (~(p - 1))) + +typedef edelib::list XsettingsList; +typedef edelib::list::iterator XsettingsListIter; struct XsmData { Window window; Atom manager_atom; Atom selection_atom; Atom xsettings_atom; - unsigned long serial; + + XsettingsList list; +}; + +struct XsettingsBuffer { + unsigned char* content; + unsigned char* pos; + int len; }; struct XsettingsColor { @@ -38,7 +57,7 @@ struct XsettingsSetting { XsettingsColor v_color; } data; - unsigned long last_changed_serial; + unsigned long last_change_serial; }; struct TimeStampInfo { @@ -75,12 +94,121 @@ Time get_server_time(Display* dpy, Window win) { return xev.xproperty.time; } +char settings_byte_order(void) { + CARD32 myint = 0x01020304; + return (*(char*)&myint == 1) ? MSBFirst : LSBFirst; +} + +bool settings_equal(const XsettingsSetting* s1, const XsettingsSetting* s2) { + EASSERT(s1 != NULL && s2 != NULL); + + if(s1->type != s2->type) + return false; + if(strcmp(s1->name, s2->name) != 0) + return false; + + switch(s1->type) { + case XS_TYPE_INT: + return s1->data.v_int == s2->data.v_int; + case XS_TYPE_COLOR: + return (s1->data.v_color.red == s2->data.v_color.red) && + (s1->data.v_color.green == s2->data.v_color.green) && + (s1->data.v_color.blue == s2->data.v_color.blue) && + (s1->data.v_color.alpha == s2->data.v_color.alpha); + case XS_TYPE_STRING: + return (strcmp(s1->data.v_string, s2->data.v_string) == 0); + } + + return false; +} + +int setting_len(const XsettingsSetting* setting) { + int len = 8; // type + pad + name-len + last-change-serial + len += XSETTINGS_PAD(strlen(setting->name), 4); + + switch(setting->type) { + case XS_TYPE_INT: + len += 4; + break; + case XS_TYPE_COLOR: + len += 8; + break; + case XS_TYPE_STRING: + len += 4 + XSETTINGS_PAD(strlen(setting->data.v_string), 4); + break; + } + + return len; +} + +void setting_store(const XsettingsSetting* setting, XsettingsBuffer* buffer) { + int len, str_len; + + *(buffer->pos++) = setting->type; + *(buffer->pos++) = 0; + + str_len = strlen(setting->name); + *(CARD16*)(buffer->pos) = str_len; + buffer->pos += 2; + + len = XSETTINGS_PAD(str_len, 4); + memcpy(buffer->pos, setting->name, str_len); + len -= str_len; + buffer->pos += str_len; + + for(; len > 0; len--) + *(buffer->pos++) = 0; + + *(CARD32*)(buffer->pos) = setting->last_change_serial; + buffer->pos += 4; + + switch(setting->type) { + case XS_TYPE_INT: + *(CARD32*)(buffer->pos) = setting->data.v_int; + buffer->pos += 4; + break; + case XS_TYPE_COLOR: + *(CARD16*)(buffer->pos) = setting->data.v_color.red; + *(CARD16*)(buffer->pos + 2) = setting->data.v_color.green; + *(CARD16*)(buffer->pos + 4) = setting->data.v_color.blue; + *(CARD16*)(buffer->pos + 6) = setting->data.v_color.alpha; + buffer->pos += 8; + break; + case XS_TYPE_STRING: + str_len = strlen(setting->data.v_string); + *(CARD32*)(buffer->pos) = str_len; + buffer->pos += 4; + + len = XSETTINGS_PAD(str_len, 4); + memcpy(buffer->pos, setting->data.v_string, str_len); + len -= str_len; + buffer->pos += str_len; + + for(; len > 0; len--) + *(buffer->pos++) = 0; + + break; + } +} + + + Xsm::Xsm() : data(NULL) { } Xsm::~Xsm() { if(data) { XDestroyWindow(fl_display, data->window); + XsettingsList& lst = data->list; + + if(!lst.empty()) { + XsettingsListIter it = lst.begin(), it_end = lst.end(); + for(; it != it_end; ++it) + delete_setting(*it); + + lst.clear(); + } + delete data; } @@ -151,3 +279,130 @@ bool Xsm::should_quit(const XEvent* xev) { return false; } +void Xsm::set_setting(const XsettingsSetting* setting) { + EASSERT(data != NULL); + + XsettingsList& lst = data->list; + XsettingsListIter it = lst.begin(), it_end = lst.end(); + + /* + * Check if entry already exists. If setting with the same + * name already exists, but with different values, that setting + * will be completely replaced with new one. + */ + for(; it != it_end; ++it) { + if(strcmp((*it)->name, setting->name) == 0) { + if(settings_equal((*it), setting)) { + return; + } else { + delete_setting(*it); + lst.erase(it); + break; + } + } + } + + XsettingsSetting* new_setting = new XsettingsSetting; + new_setting->name = strdup(setting->name); + //new_setting->last_change_serial = setting->last_change_serial; + new_setting->type = setting->type; + + switch(new_setting->type) { + case XS_TYPE_INT: + new_setting->data.v_int = setting->data.v_int; + break; + case XS_TYPE_COLOR: + new_setting->data.v_color.red = setting->data.v_color.red; + new_setting->data.v_color.green = setting->data.v_color.green; + new_setting->data.v_color.blue = setting->data.v_color.blue; + new_setting->data.v_color.alpha = setting->data.v_color.alpha; + break; + case XS_TYPE_STRING: + new_setting->data.v_string = strdup(setting->data.v_string); + break; + } + + new_setting->last_change_serial = data->serial; + lst.push_back(new_setting); +} + +void Xsm::delete_setting(XsettingsSetting* setting) { + if(!setting) + return; + + if(setting->type == XS_TYPE_STRING) + free(setting->data.v_string); + free(setting->name); + delete setting; + setting = NULL; +} + + +void Xsm::set_int(const char* name, int val) { + XsettingsSetting setting; + + setting.name = (char*)name; + setting.type = XS_TYPE_INT; + setting.data.v_int = val; + + set_setting(&setting); +} + +void Xsm::set_color(const char* name, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha) { + XsettingsSetting setting; + + setting.name = (char*)name; + setting.type = XS_TYPE_COLOR; + setting.data.v_color.red = red; + setting.data.v_color.green = green; + setting.data.v_color.blue = blue; + setting.data.v_color.alpha = alpha; + + set_setting(&setting); +} + +void Xsm::set_string(const char* name, const char* str) { + XsettingsSetting setting; + + setting.name = (char*)name; + setting.type = XS_TYPE_STRING; + setting.data.v_string = (char*)str; + + set_setting(&setting); +} + +void Xsm::notify(void) { + EASSERT(data != NULL); + + int n_settings = 0; + XsettingsBuffer buff; + + buff.len = 12; // byte-order + pad + SERIAL + N_SETTINGS + + XsettingsList& lst = data->list; + XsettingsListIter it = lst.begin(), it_end = lst.end(); + + for(; it != it_end; ++it) { + buff.len += setting_len(*it); + n_settings++; + } + + buff.content = new unsigned char[buff.len]; + buff.pos = buff.content; + + *buff.pos = settings_byte_order(); + + buff.pos += 4; + *(CARD32*)buff.pos = data->serial++; + buff.pos += 4; + *(CARD32*)buff.pos = n_settings; + buff.pos += 4; + + for(it = lst.begin(); it != it_end; ++it) + setting_store(*it, &buff); + + XChangeProperty(fl_display, data->window, data->xsettings_atom, data->xsettings_atom, + 8, PropModeReplace, buff.content, buff.len); + + delete [] buff.content; +} diff --git a/evoke/Xsm.h b/evoke/Xsm.h index aa80004..d032752 100644 --- a/evoke/Xsm.h +++ b/evoke/Xsm.h @@ -29,18 +29,25 @@ * Author of referent implementation is Owen Taylor. */ -enum XsettingsType { - XS_TYPE_INT = 0, - XS_TYPE_COLOR, - XS_TYPE_STRING -}; - struct XsmData; struct XsettingsSetting; +struct XsettingsBuffer; + +/* + * Enum order must be exact on client side too, since via these values + * client will try to decode settings. + */ +enum XsettingsType { + XS_TYPE_INT = 0, + XS_TYPE_STRING, + XS_TYPE_COLOR +}; class Xsm { private: XsmData* data; + void set_setting(const XsettingsSetting* setting); + void delete_setting(XsettingsSetting* setting); public: Xsm(); @@ -48,6 +55,12 @@ class Xsm { bool is_running(void); bool init(void); bool should_quit(const XEvent* xev); + + void set_int(const char* name, int val); + void set_color(const char* name, + unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha); + void set_string(const char* name, const char* str); + void notify(void); }; #endif