1 #include <cstdio>
2 #include <cstring>
3 #include <stdexcept>
4 #include <iostream>
5 
6 #include <json/json.h>
7 #include <auss.hpp>
8 
9 #include "i3ipc++/ipc-util.hpp"
10 #include "i3ipc++/ipc.hpp"
11 #include "i3ipc++/log.hpp"
12 
13 namespace i3ipc {
14 
15 // For log.hpp
16 std::vector<std::ostream*>  g_logging_outs = {
17 	&std::cout,
18 };
19 std::vector<std::ostream*>  g_logging_err_outs = {
20 	&std::cerr,
21 };
22 
23 #define IPC_JSON_READ(ROOT) \
24 { \
25 	Json::CharReaderBuilder b; \
26 	const std::unique_ptr<Json::CharReader> reader(b.newCharReader());	\
27 	JSONCPP_STRING error; \
28 	if(!reader->parse(buf->payload, buf->payload + buf->header->size, &ROOT, &error)) { \
29 		throw invalid_reply_payload_error(auss_t() << "Failed to parse reply on \"" i3IPC_TYPE_STR "\": " << error); \
30 	} \
31 }
32 
33 #define IPC_JSON_ASSERT_TYPE(OBJ, OBJ_DESCR, TYPE_CHECK, TYPE_NAME) \
34 	{\
35 		if (!(OBJ).TYPE_CHECK()) { \
36 			throw invalid_reply_payload_error(auss_t() << "Failed to parse reply on \"" i3IPC_TYPE_STR "\": " OBJ_DESCR " expected to be " TYPE_NAME); \
37 		} \
38 	}
39 #define IPC_JSON_ASSERT_TYPE_OBJECT(OBJ, OBJ_DESCR) IPC_JSON_ASSERT_TYPE(OBJ, OBJ_DESCR, isObject, "an object")
40 #define IPC_JSON_ASSERT_TYPE_ARRAY(OBJ, OBJ_DESCR) IPC_JSON_ASSERT_TYPE(OBJ, OBJ_DESCR, isArray, "an array")
41 #define IPC_JSON_ASSERT_TYPE_BOOL(OBJ, OBJ_DESCR) IPC_JSON_ASSERT_TYPE(OBJ, OBJ_DESCR, isBool, "a bool")
42 #define IPC_JSON_ASSERT_TYPE_INT(OBJ, OBJ_DESCR) IPC_JSON_ASSERT_TYPE(OBJ, OBJ_DESCR, isInt, "an integer")
43 
44 
parse_rect_from_json(const Json::Value & value)45 inline rect_t  parse_rect_from_json(const Json::Value&  value) {
46 	rect_t r{};
47 	r.x = value["x"].asUInt();
48 	r.y = value["y"].asUInt();
49 	r.width = value["width"].asUInt();
50 	r.height = value["height"].asUInt();
51 	return r;
52 }
53 
54 
parse_container_from_json(const Json::Value & o)55 static std::shared_ptr<container_t>  parse_container_from_json(const Json::Value&  o) {
56 #define i3IPC_TYPE_STR "PARSE CONTAINER FROM JSON"
57 	if (o.isNull())
58 		return std::shared_ptr<container_t>();
59 	std::shared_ptr<container_t>  container (new container_t());
60 	IPC_JSON_ASSERT_TYPE_OBJECT(o, "o")
61 
62 	container->id = o["id"].asUInt64();
63 	container->xwindow_id= o["window"].asUInt64();
64 	container->name = o["name"].asString();
65 	container->type = o["type"].asString();
66 	container->current_border_width = o["current_border_width"].asInt();
67 	container->percent = o["percent"].asFloat();
68 	container->rect = parse_rect_from_json(o["rect"]);
69 	container->window_rect = parse_rect_from_json(o["window_rect"]);
70 	container->deco_rect = parse_rect_from_json(o["deco_rect"]);
71 	container->geometry = parse_rect_from_json(o["geometry"]);
72 	container->urgent = o["urgent"].asBool();
73 	container->focused = o["focused"].asBool();
74 
75 	container->border = BorderStyle::UNKNOWN;
76 	std::string  border = o["border"].asString();
77 	if (border == "normal") {
78 		container->border = BorderStyle::NORMAL;
79 	} else if (border == "none") {
80 		container->border = BorderStyle::NONE;
81 	} else if (border == "pixel") {
82 		container->border = BorderStyle::PIXEL;
83 	} else if (border == "1pixel") {
84 		container->border = BorderStyle::ONE_PIXEL;
85 	} else {
86 		container->border_raw = border;
87 		I3IPC_WARN("Got a unknown \"border\" property: \"" << border << "\". Perhaps its neccessary to update i3ipc++. If you are using latest, note maintainer about this")
88 	}
89 
90 	container->layout = ContainerLayout::UNKNOWN;
91 	std::string  layout = o["layout"].asString();
92 
93 	if (layout == "splith") {
94 		container->layout = ContainerLayout::SPLIT_H;
95 	} else if (layout == "splitv") {
96 		container->layout = ContainerLayout::SPLIT_V;
97 	} else if (layout == "stacked") {
98 		container->layout = ContainerLayout::STACKED;
99 	} else if (layout == "tabbed") {
100 		container->layout = ContainerLayout::TABBED;
101 	} else if (layout == "dockarea") {
102 		container->layout = ContainerLayout::DOCKAREA;
103 	} else if (layout == "output") {
104 		container->layout = ContainerLayout::OUTPUT;
105 	} else {
106 		container->layout_raw = border;
107 		I3IPC_WARN("Got a unknown \"layout\" property: \"" << layout << "\". Perhaps its neccessary to update i3ipc++. If you are using latest, note maintainer about this")
108 	}
109 
110 	Json::Value  nodes = o["nodes"];
111 	if (!nodes.isNull()) {
112 		IPC_JSON_ASSERT_TYPE_ARRAY(nodes, "nodes")
113 		for (Json::ArrayIndex  i = 0; i < nodes.size(); i++) {
114 			container->nodes.push_back(parse_container_from_json(nodes[i]));
115 		}
116 	}
117 
118 	return container;
119 #undef i3IPC_TYPE_STR
120 }
121 
parse_workspace_from_json(const Json::Value & value)122 static std::shared_ptr<workspace_t>  parse_workspace_from_json(const Json::Value&  value) {
123 	if (value.isNull())
124 		return std::shared_ptr<workspace_t>();
125 	Json::Value  num = value["num"];
126 	Json::Value  name = value["name"];
127 	Json::Value  visible = value["visible"];
128 	Json::Value  focused = value["focused"];
129 	Json::Value  urgent = value["urgent"];
130 	Json::Value  rect = value["rect"];
131 	Json::Value  output = value["output"];
132 
133 	std::shared_ptr<workspace_t>  p (new workspace_t());
134 	p->num = num.asInt();
135 	p->name = name.asString();
136 	p->visible = visible.asBool();
137 	p->focused = focused.asBool();
138 	p->urgent = urgent.asBool();
139 	p->rect = parse_rect_from_json(rect);
140 	p->output = output.asString();
141 	return p;
142 }
143 
parse_output_from_json(const Json::Value & value)144 static std::shared_ptr<output_t>  parse_output_from_json(const Json::Value&  value) {
145 	if (value.isNull())
146 		return std::shared_ptr<output_t>();
147 	Json::Value  name = value["name"];
148 	Json::Value  active = value["active"];
149 	Json::Value  current_workspace = value["current_workspace"];
150 	Json::Value  rect = value["rect"];
151 
152 	std::shared_ptr<output_t>  p (new output_t());
153 	p->name = name.asString();
154 	p->active = active.asBool();
155 	p->current_workspace = (current_workspace.isNull() ? std::string() : current_workspace.asString());
156 	p->rect = parse_rect_from_json(rect);
157 	return p;
158 }
159 
parse_binding_from_json(const Json::Value & value)160 static std::shared_ptr<binding_t>  parse_binding_from_json(const Json::Value&  value) {
161 #define i3IPC_TYPE_STR "PARSE BINDING FROM JSON"
162 	if (value.isNull())
163 		return std::shared_ptr<binding_t>();
164 	IPC_JSON_ASSERT_TYPE_OBJECT(value, "binding")
165 	std::shared_ptr<binding_t>  b (new binding_t());
166 
167 	b->command = value["command"].asString();
168 	b->symbol = value["symbol"].asString();
169 	b->input_code = value["input_code"].asInt();
170 
171 	Json::Value input_type = value["input_type"].asString();
172 	if (input_type == "keyboard") {
173 		b->input_type = InputType::KEYBOARD;
174 	} else if (input_type == "mouse") {
175 		b->input_type = InputType::MOUSE;
176 	} else {
177 		b->input_type = InputType::UNKNOWN;
178 	}
179 
180 	Json::Value  esm_arr = value["event_state_mask"];
181 	IPC_JSON_ASSERT_TYPE_ARRAY(esm_arr, "event_state_mask")
182 
183 	b->event_state_mask.resize(esm_arr.size());
184 
185 	for (Json::ArrayIndex  i = 0; i < esm_arr.size(); i++) {
186 		b->event_state_mask[i] = esm_arr[i].asString();
187 	}
188 
189 	return b;
190 #undef i3IPC_TYPE_STR
191 }
192 
parse_mode_from_json(const Json::Value & value)193 static std::shared_ptr<mode_t>  parse_mode_from_json(const Json::Value&  value) {
194 	if (value.isNull())
195 		return std::shared_ptr<mode_t>();
196 	Json::Value  change = value["change"];
197 	Json::Value  pango_markup = value["pango_markup"];
198 
199 	std::shared_ptr<mode_t>  p (new mode_t());
200 	p->change = change.asString();
201 	p->pango_markup = pango_markup.asBool();
202 	return p;
203 }
204 
205 
parse_bar_config_from_json(const Json::Value & value)206 static std::shared_ptr<bar_config_t>  parse_bar_config_from_json(const Json::Value&  value) {
207 #define i3IPC_TYPE_STR "PARSE BAR CONFIG FROM JSON"
208 	if (value.isNull())
209 		return std::shared_ptr<bar_config_t>();
210 	IPC_JSON_ASSERT_TYPE_OBJECT(value, "(root)")
211 	std::shared_ptr<bar_config_t>  bc (new bar_config_t());
212 
213 	bc->id = value["id"].asString();
214 	bc->status_command = value["status_command"].asString();
215 	bc->font = value["font"].asString();
216 	bc->workspace_buttons = value["workspace_buttons"].asBool();
217 	bc->binding_mode_indicator = value["binding_mode_indicator"].asBool();
218 	bc->verbose = value["verbose"].asBool();
219 
220 	std::string  mode = value["mode"].asString();
221 	if (mode == "dock") {
222 		bc->mode = BarMode::DOCK;
223 	} else if (mode == "hide") {
224 		bc->mode = BarMode::HIDE;
225 	} else {
226 		bc->mode = BarMode::UNKNOWN;
227 		I3IPC_WARN("Got a unknown \"mode\" property: \"" << mode << "\". Perhaps its neccessary to update i3ipc++. If you are using latest, note maintainer about this")
228 	}
229 
230 	std::string  position = value["position"].asString();
231 	if (position == "top") {
232 		bc->position = Position::TOP;
233 	} else if (mode == "bottom") {
234 		bc->position = Position::BOTTOM;
235 	} else {
236 		bc->position = Position::UNKNOWN;
237 		I3IPC_WARN("Got a unknown \"position\" property: \"" << position << "\". Perhaps its neccessary to update i3ipc++. If you are using latest, note maintainer about this")
238 	}
239 
240 	Json::Value  colors = value["colors"];
241 	IPC_JSON_ASSERT_TYPE_OBJECT(value, "colors")
242 	auto  colors_list = colors.getMemberNames();
243 	for (auto&  m : colors_list) {
244 		bc->colors[m] = std::stoul(colors[m].asString().substr(1), nullptr, 16);
245 	}
246 
247 	return bc;
248 #undef i3IPC_TYPE_STR
249 }
250 
251 
get_socketpath()252 std::string  get_socketpath() {
253 	std::string  str;
254 	{
255 		auss_t  str_buf;
256 		FILE*  in;
257 		char  buf[512] = {0};
258 		if (!(in = popen("i3 --get-socketpath", "r"))) {
259 			throw errno_error("Failed to get socket path");
260 		}
261 
262 		while (fgets(buf, sizeof(buf), in) != nullptr) {
263 			str_buf << buf;
264 		}
265 		pclose(in);
266 		str = str_buf;
267 	}
268 	if (!str.empty() && str.back() == '\n') {
269 		str.pop_back();
270 	}
271 	return str;
272 }
273 
274 
connection(const std::string & socket_path)275 connection::connection(const std::string&  socket_path) : m_main_socket(i3_connect(socket_path)), m_event_socket(-1), m_subscriptions(0), m_socket_path(socket_path) {
276 #define i3IPC_TYPE_STR "i3's event"
277 	on_event = [this](EventType  event_type, const std::shared_ptr<const buf_t>&  buf) {
278 		switch (event_type) {
279 		case ET_WORKSPACE: {
280 			workspace_event_t  ev;
281 			Json::Value  root;
282 			IPC_JSON_READ(root);
283 			std::string  change = root["change"].asString();
284 			if (change == "focus") {
285 				ev.type = WorkspaceEventType::FOCUS;
286 			} else if (change == "init") {
287 				ev.type = WorkspaceEventType::INIT;
288 			} else if (change == "empty") {
289 				ev.type = WorkspaceEventType::EMPTY;
290 			} else if (change == "urgent") {
291 				ev.type = WorkspaceEventType::URGENT;
292 			} else if (change == "rename") {
293 				ev.type = WorkspaceEventType::RENAME;
294 			} else if (change == "reload") {
295 				ev.type = WorkspaceEventType::RELOAD;
296 			} else if (change == "restored") {
297 				ev.type = WorkspaceEventType::RESTORED;
298 			} else {
299 				I3IPC_WARN("Unknown workspace event type " << change)
300 				break;
301 			}
302 			I3IPC_DEBUG("WORKSPACE " << change)
303 
304 			Json::Value  current = root["current"];
305 			Json::Value  old = root["old"];
306 
307 			if (!current.isNull()) {
308 				ev.current = parse_workspace_from_json(current);
309 			}
310 			if (!old.isNull()) {
311 				ev.old = parse_workspace_from_json(old);
312 			}
313 
314 			if (on_workspace_event) {
315 				on_workspace_event(ev);
316 			}
317 			break;
318 		}
319 		case ET_OUTPUT:
320 			I3IPC_DEBUG("OUTPUT")
321 			if (on_output_event) {
322 				on_output_event();
323 			}
324 			break;
325 		case ET_MODE: {
326 			I3IPC_DEBUG("MODE")
327 			Json::Value  root;
328 			IPC_JSON_READ(root);
329 			std::shared_ptr<mode_t>  mode_data = parse_mode_from_json(root);
330 			if (on_mode_event) {
331 				on_mode_event(*mode_data);
332 			}
333 			break;
334 		}
335 		case ET_WINDOW: {
336 			window_event_t  ev;
337 			Json::Value  root;
338 			IPC_JSON_READ(root);
339 			std::string  change = root["change"].asString();
340 			if (change == "new") {
341 				ev.type = WindowEventType::NEW;
342 			} else if (change == "close") {
343 				ev.type = WindowEventType::CLOSE;
344 			} else if (change == "focus") {
345 				ev.type = WindowEventType::FOCUS;
346 			} else if (change == "title") {
347 				ev.type = WindowEventType::TITLE;
348 			} else if (change == "fullscreen_mode") {
349 				ev.type = WindowEventType::FULLSCREEN_MODE;
350 			} else if (change == "move") {
351 				ev.type = WindowEventType::MOVE;
352 			} else if (change == "floating") {
353 				ev.type = WindowEventType::FLOATING;
354 			} else if (change == "urgent") {
355 				ev.type = WindowEventType::URGENT;
356 			}
357 			I3IPC_DEBUG("WINDOW " << change)
358 
359 			Json::Value  container = root["container"];
360 			if (!container.isNull()) {
361 				ev.container = parse_container_from_json(container);
362 			}
363 
364 			if (on_window_event) {
365 				on_window_event(ev);
366 			}
367 			break;
368 		}
369 		case ET_BARCONFIG_UPDATE: {
370 			I3IPC_DEBUG("BARCONFIG_UPDATE")
371 			Json::Value  root;
372 			IPC_JSON_READ(root);
373 			std::shared_ptr<bar_config_t>  barconf = parse_bar_config_from_json(root);
374 			if (on_barconfig_update_event) {
375 				on_barconfig_update_event(*barconf);
376 			}
377 			break;
378 		}
379 		case ET_BINDING: {
380 			Json::Value  root;
381 			IPC_JSON_READ(root);
382 			std::string  change = root["change"].asString();
383 			if (change != "run") {
384 				I3IPC_WARN("Got \"" << change << "\" in field \"change\" of binding_event. Expected \"run\"")
385 			}
386 
387 			Json::Value  binding_json = root["binding"];
388 			std::shared_ptr<binding_t>  bptr;
389 			if (!binding_json.isNull()) {
390 				bptr = parse_binding_from_json(binding_json);
391 			}
392 
393 			if (!bptr) {
394 				I3IPC_ERR("Failed to parse field \"binding\" from binding_event")
395 			} else {
396 				I3IPC_DEBUG("BINDING " << bptr->symbol);
397 				if (on_binding_event) {
398 					on_binding_event(*bptr);
399 				}
400 			}
401 			break;
402 		}
403 		};
404 	};
405 #undef i3IPC_TYPE_STR
406 }
~connection()407 connection::~connection() {
408 	i3_disconnect(m_main_socket);
409 	if (m_event_socket > 0)
410 		this->disconnect_event_socket();
411 }
412 
413 
connect_event_socket(const bool reconnect)414 void  connection::connect_event_socket(const bool  reconnect) {
415 	if (m_event_socket > 0) {
416 		if (reconnect) {
417 			this->disconnect_event_socket();
418 		} else {
419 			I3IPC_ERR("Trying to initialize event socket secondary")
420 			return;
421 		}
422 	}
423 	m_event_socket = i3_connect(m_socket_path);
424 	this->subscribe(m_subscriptions);
425 }
426 
427 
disconnect_event_socket()428 void  connection::disconnect_event_socket() {
429 	if (m_event_socket <= 0) {
430 		I3IPC_WARN("Trying to disconnect non-connected event socket")
431 		return;
432 	}
433 	i3_disconnect(m_event_socket);
434 }
435 
436 
handle_event()437 bool connection::handle_event() {
438 	if (m_event_socket <= 0) {
439 		this->connect_event_socket();
440 	}
441 
442 	auto buf = i3_recv(m_event_socket);
443 
444 	if (buf && this->on_event) {
445 		this->on_event(static_cast<EventType>(1 << (buf->header->type & 0x7f)), std::static_pointer_cast<const buf_t>(buf));
446 	} else if (buf) {
447 		return true;
448 	}
449 	return false;
450 }
451 
452 
subscribe(const int32_t events)453 bool  connection::subscribe(const int32_t  events) {
454 #define i3IPC_TYPE_STR "SUBSCRIBE"
455 	if (m_event_socket <= 0) {
456 		m_subscriptions |= events;
457 		return true;
458 	}
459 	std::string  payload;
460 	{
461 		auss_t  payload_auss;
462 		if (events & static_cast<int32_t>(ET_WORKSPACE)) {
463 			payload_auss << "\"workspace\",";
464 		}
465 		if (events & static_cast<int32_t>(ET_OUTPUT)) {
466 			payload_auss << "\"output\",";
467 		}
468 		if (events & static_cast<int32_t>(ET_MODE)) {
469 			payload_auss << "\"mode\",";
470 		}
471 		if (events & static_cast<int32_t>(ET_WINDOW)) {
472 			payload_auss << "\"window\",";
473 		}
474 		if (events & static_cast<int32_t>(ET_BARCONFIG_UPDATE)) {
475 			payload_auss << "\"barconfig_update\",";
476 		}
477 		if (events & static_cast<int32_t>(ET_BINDING)) {
478 			payload_auss << "\"binding\",";
479 		}
480 		payload = payload_auss;
481 		if (payload.empty()) {
482 			return true;
483 		}
484 		payload.pop_back();
485 	}
486 	I3IPC_DEBUG("i3 IPC subscriptions: " << payload)
487 
488 	auto  buf = i3_msg(m_event_socket, ClientMessageType::SUBSCRIBE, auss_t() << '[' << payload << ']');
489 	Json::Value  root;
490 	IPC_JSON_READ(root)
491 
492 	m_subscriptions |= events;
493 
494 	return root["success"].asBool();
495 #undef i3IPC_TYPE_STR
496 }
497 
498 
get_version() const499 version_t  connection::get_version() const {
500 #define i3IPC_TYPE_STR "GET_VERSION"
501 	auto  buf = i3_msg(m_main_socket, ClientMessageType::GET_VERSION);
502 	Json::Value  root;
503 	IPC_JSON_READ(root)
504 	IPC_JSON_ASSERT_TYPE_OBJECT(root, "root")
505 
506 	version_t v{};
507 	v.human_readable = root["human_readable"].asString();
508 	v.loaded_config_file_name = root["loaded_config_file_name"].asString();
509 	v.major = root["major"].asUInt();
510 	v.minor = root["minor"].asUInt();
511 	v.patch = root["patch"].asUInt();
512 	return v;
513 #undef i3IPC_TYPE_STR
514 }
515 
516 
get_tree() const517 std::shared_ptr<container_t>  connection::get_tree() const {
518 #define i3IPC_TYPE_STR "GET_TREE"
519 	auto  buf = i3_msg(m_main_socket, ClientMessageType::GET_TREE);
520 	Json::Value  root;
521 	IPC_JSON_READ(root);
522 	return parse_container_from_json(root);
523 #undef i3IPC_TYPE_STR
524 }
525 
526 
get_outputs() const527 std::vector< std::shared_ptr<output_t> >  connection::get_outputs() const {
528 #define i3IPC_TYPE_STR "GET_OUTPUTS"
529 	auto  buf = i3_msg(m_main_socket, ClientMessageType::GET_OUTPUTS);
530 	Json::Value  root;
531 	IPC_JSON_READ(root)
532 	IPC_JSON_ASSERT_TYPE_ARRAY(root, "root")
533 
534 	std::vector< std::shared_ptr<output_t> >  outputs;
535 
536 	for (auto w : root) {
537 		outputs.push_back(parse_output_from_json(w));
538 	}
539 
540 	return outputs;
541 #undef i3IPC_TYPE_STR
542 }
543 
544 
get_workspaces() const545 std::vector< std::shared_ptr<workspace_t> >  connection::get_workspaces() const {
546 #define i3IPC_TYPE_STR "GET_WORKSPACES"
547 	auto  buf = i3_msg(m_main_socket, ClientMessageType::GET_WORKSPACES);
548 	Json::Value  root;
549 	IPC_JSON_READ(root)
550 	IPC_JSON_ASSERT_TYPE_ARRAY(root, "root")
551 
552 	std::vector< std::shared_ptr<workspace_t> >  workspaces;
553 
554 	for (auto w : root) {
555 		workspaces.push_back(parse_workspace_from_json(w));
556 	}
557 
558 	return workspaces;
559 #undef i3IPC_TYPE_STR
560 }
561 
562 
get_bar_configs_list() const563 std::vector<std::string>  connection::get_bar_configs_list() const {
564 #define i3IPC_TYPE_STR "GET_BAR_CONFIG (get_bar_configs_list)"
565 	auto  buf = i3_msg(m_main_socket, ClientMessageType::GET_BAR_CONFIG);
566 	Json::Value  root;
567 	IPC_JSON_READ(root)
568 	IPC_JSON_ASSERT_TYPE_ARRAY(root, "root")
569 
570 	std::vector<std::string>  l;
571 
572 	for (auto w : root) {
573 		l.push_back(w.asString());
574 	}
575 
576 	return l;
577 #undef i3IPC_TYPE_STR
578 }
579 
580 
get_bar_config(const std::string & name) const581 std::shared_ptr<bar_config_t>  connection::get_bar_config(const std::string&  name) const {
582 #define i3IPC_TYPE_STR "GET_BAR_CONFIG"
583 	auto  buf = i3_msg(m_main_socket, ClientMessageType::GET_BAR_CONFIG, name);
584 	Json::Value  root;
585 	IPC_JSON_READ(root)
586 	return parse_bar_config_from_json(root);
587 #undef i3IPC_TYPE_STR
588 }
589 
590 
send_command(const std::string & command) const591 bool  connection::send_command(const std::string&  command) const {
592 #define i3IPC_TYPE_STR "COMMAND"
593 	auto  buf = i3_msg(m_main_socket, ClientMessageType::COMMAND, command);
594 	Json::Value  root;
595 	IPC_JSON_READ(root)
596 	IPC_JSON_ASSERT_TYPE_ARRAY(root, "root")
597 	Json::Value  payload = root[0];
598 	IPC_JSON_ASSERT_TYPE_OBJECT(payload, " first item of root")
599 
600 	if (payload["success"].asBool()) {
601 		return true;
602 	} else {
603 		Json::Value  error = payload["error"];
604 		if (!error.isNull()) {
605 			I3IPC_ERR("Failed to execute command: " << error.asString())
606 		}
607 		return false;
608 	}
609 #undef i3IPC_TYPE_STR
610 }
611 
get_main_socket_fd()612 int32_t  connection::get_main_socket_fd() { return m_main_socket; }
613 
get_event_socket_fd()614 int32_t  connection::get_event_socket_fd() { return m_event_socket; }
615 
616 
get_version()617 const version_t&  get_version() {
618 #define I3IPC_VERSION_MAJOR  0
619 #define I3IPC_VERSION_MINOR  4
620 #define I3IPC_VERSION_PATCH  0
621 	static version_t v{};
622 	v.human_readable = auss_t() << I3IPC_VERSION_MAJOR << '.' << I3IPC_VERSION_MINOR << '.' << I3IPC_VERSION_PATCH;
623 	v.loaded_config_file_name = std::string();
624 	v.major = I3IPC_VERSION_MAJOR;
625 	v.minor = I3IPC_VERSION_MINOR;
626 	v.patch = I3IPC_VERSION_PATCH;
627 	return v;
628 }
629 
630 }
631