1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
// Copyright 2009 Daniel Erat <dan@erat.org>
// All rights reserved.
#include <cassert>
#include <cstdio>
#include <cstring>
#include <getopt.h>
#include <stdint.h>
#include <string>
#include <unistd.h>
#include <X11/Xlib.h>
#include "common.h"
#include "data_reader.h"
#include "setting.h"
using std::min;
using std::string;
namespace xsettingsd {
bool GetData(int screen, char* buffer, size_t buffer_size, size_t* data_size) {
assert(data_size);
Display* display = XOpenDisplay(NULL);
if (!display) {
fprintf(stderr, "Couldn't open display\n");
return false;
}
string sel_name = StringPrintf("_XSETTINGS_S%d", screen);
Atom sel_atom = XInternAtom(display, sel_name.c_str(), False);
Window win = XGetSelectionOwner(display, sel_atom);
if (win == None) {
fprintf(stderr, "No current owner for %s selection\n", sel_name.c_str());
return false;
}
static const char* kPropName = "_XSETTINGS_SETTINGS";
Atom prop_atom = XInternAtom(display, kPropName, False);
Atom type_ret = None;
int format_ret = 0;
unsigned long num_items_ret = 0;
unsigned long rem_bytes_ret = 0;
unsigned char* prop_ret = NULL;
int retval = XGetWindowProperty(display,
win,
prop_atom,
0, // offset
buffer_size / 4, // length (32-bit multiples)
False, // delete
AnyPropertyType, // type
&type_ret, // actual type
&format_ret, // actual format
&num_items_ret, // actual num items
&rem_bytes_ret, // remaining bytes
&prop_ret); // property
if (retval != Success) {
fprintf(stderr, "XGetWindowProperty() returned %d\n", retval);
return false;
}
if (num_items_ret == 0) {
fprintf(stderr, "Property %s doesn't exist on 0x%x\n",
kPropName, static_cast<unsigned int>(win));
return false;
}
if (rem_bytes_ret > 0) {
fprintf(stderr, "Property %s on 0x%x is more than %zu bytes (%lu remain)\n",
kPropName, static_cast<unsigned int>(win), buffer_size,
rem_bytes_ret);
XFree(prop_ret);
return false;
}
if (format_ret != 8) {
fprintf(stderr, "Got unexpected format %d\n", format_ret);
XFree(prop_ret);
return false;
}
*data_size = min(buffer_size, static_cast<size_t>(num_items_ret));
memcpy(buffer, prop_ret, *data_size);
return true;
}
bool DumpSetting(DataReader* reader) {
int8_t type_byte = 0;
if (!reader->ReadInt8(&type_byte)) {
fprintf(stderr, "Unable to read setting type\n");
return false;
}
Setting::Type type = static_cast<Setting::Type>(type_byte);
if (type != Setting::TYPE_INTEGER &&
type != Setting::TYPE_STRING &&
type != Setting::TYPE_COLOR) {
fprintf(stderr, "Got setting with unhandled type %d\n", type);
return false;
}
if (!reader->ReadBytes(NULL, 1)) {
fprintf(stderr, "Unable to read 1-byte setting padding\n");
return false;
}
uint16_t name_size = 0;
if (!reader->ReadInt16(reinterpret_cast<int16_t*>(&name_size))) {
fprintf(stderr, "Unable to read setting name size\n");
return false;
}
string name;
if (!reader->ReadBytes(&name, name_size)) {
fprintf(stderr, "Unable to read %u-byte setting name\n", name_size);
return false;
}
size_t name_padding = GetPadding(name_size, 4);
if (!reader->ReadBytes(NULL, name_padding)) {
fprintf(stderr, "Unable to read %zu-byte setting name padding\n",
name_padding);
return false;
}
if (!reader->ReadBytes(NULL, 4)) {
fprintf(stderr, "Unable to read setting serial number\n");
return false;
}
if (type == Setting::TYPE_INTEGER) {
int32_t value = 0;
if (!reader->ReadInt32(&value)) {
fprintf(stderr, "Unable to read integer setting value\n");
return false;
}
printf("%s %d\n", name.c_str(), value);
} else if (type == Setting::TYPE_STRING) {
uint32_t value_size = 0;
if (!reader->ReadInt32(reinterpret_cast<int32_t*>(&value_size))) {
fprintf(stderr, "Unable to read string setting value size\n");
return false;
}
string value;
if (!reader->ReadBytes(&value, value_size)) {
fprintf(stderr, "Unable to read %u-byte string setting value\n",
value_size);
return false;
}
size_t value_padding = GetPadding(value_size, 4);
if (!reader->ReadBytes(NULL, value_padding)) {
fprintf(stderr, "Unable to read %zu-byte string setting value padding\n",
value_padding);
return false;
}
string escaped_value;
for (size_t i = 0; i < value.size(); ++i) {
char ch = value.c_str()[i];
switch (ch) {
case '\n':
escaped_value.append("\\n");
break;
case '"':
escaped_value.append("\\\"");
break;
default:
escaped_value.push_back(ch);
}
}
printf("%s \"%s\"\n", name.c_str(), escaped_value.c_str());
} else if (type == Setting::TYPE_COLOR) {
uint16_t red = 0, blue = 0, green = 0, alpha = 0;
if (!reader->ReadInt16(reinterpret_cast<int16_t*>(&red)) ||
!reader->ReadInt16(reinterpret_cast<int16_t*>(&blue)) ||
!reader->ReadInt16(reinterpret_cast<int16_t*>(&green)) ||
!reader->ReadInt16(reinterpret_cast<int16_t*>(&alpha))) {
fprintf(stderr, "Unable to read color values\n");
return false;
}
// Note that unlike the spec, our config uses RGB-order, not RBG.
printf("%s (%u, %u, %u, %u)\n", name.c_str(), red, green, blue, alpha);
} else {
assert(false);
}
return true;
}
bool DumpSettings(DataReader* reader) {
int byte_order = IsLittleEndian() ? LSBFirst : MSBFirst;
// Read 1-byte byte order.
int8_t prop_byte_order = 0;
if (!reader->ReadInt8(&prop_byte_order)) {
fprintf(stderr, "Couldn't read byte order\n");
return false;
}
if (prop_byte_order != byte_order) {
reader->set_reverse_bytes(true);
}
// Read 3 bytes of padding and 4-byte serial.
if (!reader->ReadBytes(NULL, 7)) {
fprintf(stderr, "Unable to read header\n");
return false;
}
uint32_t num_settings = 0;
if (!reader->ReadInt32(reinterpret_cast<int32_t*>(&num_settings))) {
fprintf(stderr, "Unable to read number of settings\n");
return false;
}
for (uint32_t i = 0; i < num_settings; ++i) {
if (!DumpSetting(reader))
return false;
}
return true;
}
} // namespace xsettingsd
int main(int argc, char** argv) {
static const char* kUsage =
"Usage: dump_xsettings [OPTION] ...\n"
"\n"
"Dump current XSETTINGS values in xsettingd's format.\n"
"\n"
"Options: -h, --help print this help message\n"
" -s, --screen=SCREEN screen to use (default is 0)\n";
int screen = 0;
struct option options[] = {
{ "help", 0, NULL, 'h', },
{ "screen", 1, NULL, 's', },
{ NULL, 0, NULL, 0 },
};
opterr = 0;
while (true) {
int ch = getopt_long(argc, argv, "hs:", options, NULL);
if (ch == -1) {
break;
} else if (ch == 'h' || ch == '?') {
fprintf(stderr, "%s", kUsage);
return 1;
} else if (ch == 's') {
char* endptr = NULL;
screen = strtol(optarg, &endptr, 10);
if (optarg[0] == '\0' || endptr[0] != '\0' || screen < 0) {
fprintf(stderr, "Invalid screen \"%s\"\n", optarg);
return 1;
}
}
}
static const size_t kBufferSize = 2 << 15;
char buffer[kBufferSize];
size_t data_size = 0;
if (!xsettingsd::GetData(screen, buffer, kBufferSize, &data_size))
return 1;
assert(data_size <= kBufferSize);
xsettingsd::DataReader reader(buffer, data_size);
if (!xsettingsd::DumpSettings(&reader))
return 1;
return 0;
}
|