Did the merge work?
This commit is contained in:
14
CHANGELOG
Normal file
14
CHANGELOG
Normal file
@@ -0,0 +1,14 @@
|
||||
0.2.1
|
||||
+ Added example of event handling
|
||||
* Fixed SIGSEGV in parse_*_from_json functions
|
||||
|
||||
0.2.0
|
||||
+ Implemented GET_TREE (i3ipc::connection::get_tree())
|
||||
|
||||
~ Shipping all available payload with workspace and window events (issue #2)
|
||||
~ i3ipc::I3Connection renamed to i3ipc::connection
|
||||
|
||||
~ Internal refreactoring
|
||||
|
||||
* Fixing failed build: Parts of a struct were initialised in wrong order, C99-style designated initialisers did not prevent this from causing an error [mox]
|
||||
* Minor documentation and code fixies
|
||||
@@ -29,7 +29,7 @@ include_directories(
|
||||
)
|
||||
|
||||
link_directories(
|
||||
${SIBCPP_LIBRARY_DIRS}
|
||||
${SIGCPP_LIBRARY_DIRS}
|
||||
3rd/jsoncpp/src/lib_json/
|
||||
)
|
||||
|
||||
@@ -42,6 +42,7 @@ add_library(i3ipc++_static STATIC ${SRC})
|
||||
|
||||
set(I3IPCpp_LIBRARY_DIRS ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(I3IPCpp_INCLUDE_DIRS
|
||||
${SIGCPP_INCLUDE_DIRS}
|
||||
3rd/auss/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/
|
||||
)
|
||||
|
||||
@@ -15,3 +15,6 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
|
||||
|
||||
add_executable(workspaces workspaces.cpp)
|
||||
target_link_libraries(workspaces ${I3IPCpp_LIBRARIES})
|
||||
|
||||
add_executable(events events.cpp)
|
||||
target_link_libraries(events ${I3IPCpp_LIBRARIES})
|
||||
|
||||
25
examples/events.cpp
Normal file
25
examples/events.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <i3ipc++/ipc.hpp>
|
||||
|
||||
|
||||
int main() {
|
||||
i3ipc::connection conn;
|
||||
conn.subscribe(i3ipc::ET_WORKSPACE | i3ipc::ET_WINDOW);
|
||||
|
||||
conn.signal_workspace_event.connect([](const i3ipc::workspace_event_t& ev) {
|
||||
std::cout << "workspace_event: " << (char)ev.type << std::endl;
|
||||
});
|
||||
conn.signal_window_event.connect([](const i3ipc::window_event_t& ev) {
|
||||
std::cout << "window_event: " << (char)ev.type << std::endl;
|
||||
});
|
||||
|
||||
// Don't forget this:
|
||||
conn.prepare_to_event_handling();
|
||||
|
||||
while (true) {
|
||||
conn.handle_event();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,21 +2,49 @@
|
||||
|
||||
#include <i3ipc++/ipc.hpp>
|
||||
|
||||
|
||||
void dump_tree_container(const i3ipc::container_t& c, std::string& prefix) {
|
||||
std::cout << prefix << "ID: " << c.id << " (i3's; X11's - " << c.xwindow_id << ")" << std::endl;
|
||||
prefix.push_back('\t');
|
||||
std::cout << prefix << "name = \"" << c.name << "\"" << std::endl;
|
||||
std::cout << prefix << "type = \"" << c.type << "\"" << std::endl;
|
||||
std::cout << prefix << "border = \"" << c.border_raw << "\"" << std::endl;
|
||||
std::cout << prefix << "current_border_width = " << c.current_border_width << std::endl;
|
||||
std::cout << prefix << "layout = \"" << c.layout_raw << "\"" << std::endl;
|
||||
std::cout << prefix << "percent = " << c.percent << std::endl;
|
||||
if (c.urgent) {
|
||||
std::cout << prefix << "urgent" << std::endl;
|
||||
}
|
||||
if (c.focused) {
|
||||
std::cout << prefix << "focused" << std::endl;
|
||||
}
|
||||
prefix.push_back('\t');
|
||||
for (auto& n : c.nodes) {
|
||||
dump_tree_container(*n, prefix);
|
||||
}
|
||||
prefix.pop_back();
|
||||
prefix.pop_back();
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
i3ipc::I3Connection conn;
|
||||
i3ipc::connection conn;
|
||||
for (auto& w : conn.get_workspaces()) {
|
||||
std::cout << '#' << std::hex << w.num << std::dec
|
||||
<< "\n\tName: " << w.name
|
||||
<< "\n\tVisible: " << w.visible
|
||||
<< "\n\tFocused: " << w.focused
|
||||
<< "\n\tUrgent: " << w.urgent
|
||||
std::cout << '#' << std::hex << w->num << std::dec
|
||||
<< "\n\tName: " << w->name
|
||||
<< "\n\tVisible: " << w->visible
|
||||
<< "\n\tFocused: " << w->focused
|
||||
<< "\n\tUrgent: " << w->urgent
|
||||
<< "\n\tRect: "
|
||||
<< "\n\t\tX: " << w.rect.x
|
||||
<< "\n\t\tY: " << w.rect.y
|
||||
<< "\n\t\tWidth: " << w.rect.width
|
||||
<< "\n\t\tHeight: " << w.rect.height
|
||||
<< "\n\tOutput: " << w.output
|
||||
<< "\n\t\tX: " << w->rect.x
|
||||
<< "\n\t\tY: " << w->rect.y
|
||||
<< "\n\t\tWidth: " << w->rect.width
|
||||
<< "\n\t\tHeight: " << w->rect.height
|
||||
<< "\n\tOutput: " << w->output
|
||||
<< std::endl;
|
||||
}
|
||||
std::string prefix_buf;
|
||||
dump_tree_container(*conn.get_tree(), prefix_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace i3ipc {
|
||||
*/
|
||||
struct header_t {
|
||||
/* 6 = strlen(I3_IPC_MAGIC) */
|
||||
char magic[6]; /**< Magic string @see I3_IPC_MAGIC */
|
||||
uint32_t size; /**< Size of payload */
|
||||
uint32_t type; /**< Message type */
|
||||
char magic[6]; ///< Magic string @see I3_IPC_MAGIC
|
||||
uint32_t size; ///< Size of payload
|
||||
uint32_t type; ///< Message type
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ enum class ReplyType : uint32_t {
|
||||
* @brief i3 IPC message buffer
|
||||
*/
|
||||
struct buf_t {
|
||||
uint32_t size; /**< @brief Size of whole buffer */
|
||||
uint8_t* data; /**< @brief Pointer to the message */
|
||||
uint32_t size; ///< @brief Size of whole buffer
|
||||
uint8_t* data; ///< @brief Pointer to the message
|
||||
|
||||
/**
|
||||
* @brief i3 IPC message header
|
||||
|
||||
@@ -33,55 +33,56 @@ std::string get_socketpath();
|
||||
* Primitive of rectangle
|
||||
*/
|
||||
struct rect_t {
|
||||
int x; /**< Position on X axis */
|
||||
int y; /**< Position on Y axis */
|
||||
int width; /**< Width of rectangle */
|
||||
int height; /**< Height of rectangle */
|
||||
int x; ///< Position on X axis
|
||||
int y; ///< Position on Y axis
|
||||
int width; ///< Width of rectangle
|
||||
int height; ///< Height of rectangle
|
||||
};
|
||||
|
||||
/**
|
||||
* i3's workspace
|
||||
*/
|
||||
struct workspace_t {
|
||||
int num; /**< Index of the worksapce */
|
||||
std::string name; /**< Name of the workspace */
|
||||
bool visible; /**< Is the workspace visible */
|
||||
bool focused; /**< Is the workspace is currently focused */
|
||||
bool urgent; /**< Is the workspace is urgent */
|
||||
rect_t rect; /**< A size of the workspace */
|
||||
std::string output; /**< An output of the workspace */
|
||||
int num; ///< Index of the worksapce
|
||||
std::string name; ///< Name of the workspace
|
||||
bool visible; ///< Is the workspace visible
|
||||
bool focused; ///< Is the workspace is currently focused
|
||||
bool urgent; ///< Is the workspace is urgent
|
||||
rect_t rect; ///< A size of the workspace
|
||||
std::string output; ///< An output of the workspace
|
||||
};
|
||||
|
||||
/**
|
||||
* i3's output
|
||||
*/
|
||||
struct output_t {
|
||||
std::string name; /**< Name of the output */
|
||||
bool active; /**< Is the output currently active */
|
||||
std::string current_workspace; /**< Name of current workspace */
|
||||
rect_t rect; /**< Size of the output */
|
||||
std::string name; ///< Name of the output
|
||||
bool active; ///< Is the output currently active
|
||||
std::string current_workspace; ///< Name of current workspace
|
||||
rect_t rect; ///< Size of the output
|
||||
};
|
||||
|
||||
/**
|
||||
* Version of i3
|
||||
*/
|
||||
struct version_t {
|
||||
std::string human_readable; /**< Human redable version string */
|
||||
std::string loaded_config_file_name; /**< Path to current config of i3 */
|
||||
uint32_t major; /**< Major version of i3 */
|
||||
uint32_t minor; /**< Minor version of i3 */
|
||||
uint32_t patch; /**< Patch number of i3 */
|
||||
std::string human_readable; ///< Human redable version string
|
||||
std::string loaded_config_file_name; ///< Path to current config of i3
|
||||
uint32_t major; ///< Major version of i3
|
||||
uint32_t minor; ///< Minor version of i3
|
||||
uint32_t patch; ///< Patch number of i3
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Types of the events of i3
|
||||
*/
|
||||
enum EventType {
|
||||
ET_WORKSPACE = (1 << 0), /**< Workspace event */
|
||||
ET_OUTPUT = (1 << 1), /**< Output event */
|
||||
ET_MODE = (1 << 2), /**< Output mode event */
|
||||
ET_WINDOW = (1 << 3), /**< Window event */
|
||||
ET_BARCONFIG_UPDATE = (1 << 4), /**< Bar config update event @attention Yet is not implemented as signal in I3Connection */
|
||||
ET_WORKSPACE = (1 << 0), ///< Workspace event
|
||||
ET_OUTPUT = (1 << 1), ///< Output event
|
||||
ET_MODE = (1 << 2), ///< Output mode event
|
||||
ET_WINDOW = (1 << 3), ///< Window event
|
||||
ET_BARCONFIG_UPDATE = (1 << 4), ///< Bar config update event @attention Yet is not implemented as signal in connection
|
||||
};
|
||||
|
||||
#ifndef I3IPCpp_USE_FULL_SIGNALS
|
||||
@@ -89,39 +90,109 @@ enum EventType {
|
||||
* Types of workspace events
|
||||
*/
|
||||
enum class WorkspaceEventType : char {
|
||||
FOCUS = 'f', /**< Focused */
|
||||
INIT = 'i', /**< Initialized */
|
||||
EMPTY = 'e', /**< Became empty */
|
||||
URGENT = 'u', /**< Became urgent */
|
||||
FOCUS = 'f', ///< Focused
|
||||
INIT = 'i', ///< Initialized
|
||||
EMPTY = 'e', ///< Became empty
|
||||
URGENT = 'u', ///< Became urgent
|
||||
};
|
||||
|
||||
/**
|
||||
* Types of window events
|
||||
*/
|
||||
enum class WindowEventType : char {
|
||||
NEW = 'n', /**< Window created */
|
||||
CLOSE = 'c', /**< Window closed */
|
||||
FOCUS = 'f', /**< Window got focus */
|
||||
TITLE = 't', /**< Title of window has been changed */
|
||||
FULLSCREEN_MODE = 'F', /**< Window toggled to fullscreen mode */
|
||||
MOVE = 'M', /**< Window moved */
|
||||
FLOATING = '_', /**< Window toggled floating mode */
|
||||
URGENT = 'u', /**< Window became urgent */
|
||||
NEW = 'n', ///< Window created
|
||||
CLOSE = 'c', ///< Window closed
|
||||
FOCUS = 'f', ///< Window got focus
|
||||
TITLE = 't', ///< Title of window has been changed
|
||||
FULLSCREEN_MODE = 'F', ///< Window toggled to fullscreen mode
|
||||
MOVE = 'M', ///< Window moved
|
||||
FLOATING = '_', ///< Window toggled floating mode
|
||||
URGENT = 'u', ///< Window became urgent
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A style of a container's border
|
||||
*/
|
||||
enum class BorderStyle : char {
|
||||
UNKNOWN = '?', //< If got an unknown border style in reply
|
||||
NONE = 'N',
|
||||
NORMAL = 'n',
|
||||
ONE_PIXEL = '1',
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A type of a container's layout
|
||||
*/
|
||||
enum class ContainerLayout : char {
|
||||
UNKNOWN = '?', //< If got an unknown border style in reply
|
||||
SPLIT_H = 'h',
|
||||
SPLIT_V = 'v',
|
||||
STACKED = 's',
|
||||
TABBED = 't',
|
||||
DOCKAREA = 'd',
|
||||
OUTPUT = 'o',
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A node of tree of windows
|
||||
*/
|
||||
struct container_t {
|
||||
uint64_t id; ///< The internal ID (actually a C pointer value) of this container. Do not make any assumptions about it. You can use it to (re-)identify and address containers when talking to i3
|
||||
uint64_t xwindow_id; ///< The X11 window ID of the actual client window inside this container. This field is set to null for split containers or otherwise empty containers. This ID corresponds to what xwininfo(1) and other X11-related tools display (usually in hex)
|
||||
std::string name; ///< The internal name of this container. For all containers which are part of the tree structure down to the workspace contents, this is set to a nice human-readable name of the container. For containers that have an X11 window, the content is the title (_NET_WM_NAME property) of that window. For all other containers, the content is not defined (yet)
|
||||
std::string type; ///< Type of this container
|
||||
BorderStyle border; ///< A style of the container's border
|
||||
std::string border_raw; ///< A "border" field of TREE reply. NOT empty only if border equals BorderStyle::UNKNOWN
|
||||
uint32_t current_border_width; ///< Number of pixels of the border width
|
||||
ContainerLayout layout; ///< A type of the container's layout
|
||||
std::string layout_raw; ///< A "layout" field of TREE reply. NOT empty only if layout equals ContainerLayout::UNKNOWN
|
||||
float percent; ///< The percentage which this container takes in its parent. A value of < 0 means that the percent property does not make sense for this container, for example for the root container.
|
||||
rect_t rect; ///< The absolute display coordinates for this container
|
||||
rect_t window_rect; ///< The coordinates of the actual client window inside its container. These coordinates are relative to the container and do not include the window decoration (which is actually rendered on the parent container)
|
||||
rect_t deco_rect; ///< The coordinates of the window decoration inside its container. These coordinates are relative to the container and do not include the actual client window
|
||||
rect_t geometry; ///< The original geometry the window specified when i3 mapped it. Used when switching a window to floating mode, for example
|
||||
bool urgent;
|
||||
bool focused;
|
||||
|
||||
std::list< std::shared_ptr<container_t> > nodes;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* A workspace event
|
||||
*/
|
||||
struct workspace_event_t {
|
||||
WorkspaceEventType type;
|
||||
std::shared_ptr<workspace_t> current; ///< Current focused workspace
|
||||
std::shared_ptr<workspace_t> old; ///< Old (previous) workspace @note With some WindowEventType could be null
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A window event
|
||||
*/
|
||||
struct window_event_t {
|
||||
WindowEventType type;
|
||||
std::shared_ptr<container_t> container; ///< A container event associated with @note With some WindowEventType could be null
|
||||
};
|
||||
|
||||
|
||||
struct buf_t;
|
||||
/**
|
||||
* Connection to the i3
|
||||
*/
|
||||
class I3Connection {
|
||||
class connection {
|
||||
public:
|
||||
/**
|
||||
* Connect to the i3
|
||||
* @param socket_path path to a i3 IPC socket
|
||||
*/
|
||||
I3Connection(const std::string& socket_path = get_socketpath());
|
||||
~I3Connection();
|
||||
connection(const std::string& socket_path = get_socketpath());
|
||||
~connection();
|
||||
|
||||
/**
|
||||
* Send a command to i3
|
||||
@@ -134,13 +205,13 @@ public:
|
||||
* Request a list of workspaces
|
||||
* @return List of workspaces
|
||||
*/
|
||||
std::vector<workspace_t> get_workspaces() const;
|
||||
std::vector< std::shared_ptr<workspace_t> > get_workspaces() const;
|
||||
|
||||
/**
|
||||
* Request a list of outputs
|
||||
* @return List of outputs
|
||||
*/
|
||||
std::vector<output_t> get_outputs() const;
|
||||
std::vector< std::shared_ptr<output_t> > get_outputs() const;
|
||||
|
||||
/**
|
||||
* Request a version of i3
|
||||
@@ -148,6 +219,12 @@ public:
|
||||
*/
|
||||
version_t get_version() const;
|
||||
|
||||
/**
|
||||
* Request a tree of windows
|
||||
* @return A root container
|
||||
*/
|
||||
std::shared_ptr<container_t> get_tree() const;
|
||||
|
||||
/**
|
||||
* Subscribe on an events of i3
|
||||
*
|
||||
@@ -156,7 +233,7 @@ public:
|
||||
*
|
||||
* Example:
|
||||
* @code{.cpp}
|
||||
* I3Connection conn;
|
||||
* connection conn;
|
||||
* conn.subscribe(i3ipc::ipc::ET_WORKSPACE | i3ipc::ipc::ET_WINDOW);
|
||||
* @endcode
|
||||
*
|
||||
@@ -177,17 +254,18 @@ public:
|
||||
*/
|
||||
void handle_event();
|
||||
|
||||
sigc::signal<void> signal_output_event; /**< Output event signal */
|
||||
sigc::signal<void> signal_mode_event; /**< Output mode event signal */
|
||||
sigc::signal<void> signal_barconfig_update_event; /**< Barconfig update event signal */
|
||||
#ifdef I3IPCpp_USE_FULL_SIGNALS
|
||||
sigc::signal<void, const Json::Value&> signal_workspace_event; /**< Workspace event signal */
|
||||
sigc::signal<void, const Json::Value&> signal_window_event; /**< Window event signal */
|
||||
#else
|
||||
sigc::signal<void, WorkspaceEventType> signal_workspace_event; /**< Workspace event signal */
|
||||
sigc::signal<void, WindowEventType> signal_window_event; /**< Window event signal */
|
||||
#endif
|
||||
sigc::signal<void, EventType, const std::shared_ptr<const buf_t>&> signal_event; /**< i3 event signal @note Default handler routes event to signal according to type */
|
||||
/**
|
||||
* Get the file descriptor associated to i3.
|
||||
* @return the file descriptor associated to i3, -1 if not created yet.
|
||||
*/
|
||||
int32_t get_file_descriptor();
|
||||
|
||||
sigc::signal<void, const workspace_event_t&> signal_workspace_event; ///< Workspace event signal
|
||||
sigc::signal<void> signal_output_event; ///< Output event signal
|
||||
sigc::signal<void> signal_mode_event; ///< Output mode event signal
|
||||
sigc::signal<void, const window_event_t&> signal_window_event; ///< Window event signal
|
||||
sigc::signal<void> signal_barconfig_update_event; ///< Barconfig update event signal
|
||||
sigc::signal<void, EventType, const std::shared_ptr<const buf_t>&> signal_event; ///< i3 event signal @note Default handler routes event to signal according to type
|
||||
private:
|
||||
const int32_t m_main_socket;
|
||||
int32_t m_event_socket;
|
||||
|
||||
226
src/ipc.cpp
226
src/ipc.cpp
@@ -52,6 +52,110 @@ inline rect_t parse_rect_from_json(const Json::Value& value) {
|
||||
}
|
||||
|
||||
|
||||
static std::shared_ptr<container_t> parse_container_from_json(const Json::Value& o) {
|
||||
#define i3IPC_TYPE_STR "PARSE CONTAINER FROM JSON"
|
||||
if (o.isNull())
|
||||
return std::shared_ptr<container_t>();
|
||||
std::shared_ptr<container_t> container (new container_t());
|
||||
IPC_JSON_ASSERT_TYPE_OBJECT(o, "o")
|
||||
|
||||
container->id = o["id"].asUInt64();
|
||||
container->xwindow_id= o["window"].asUInt64();
|
||||
container->name = o["name"].asString();
|
||||
container->type = o["type"].asString();
|
||||
container->current_border_width = o["current_border_width"].asInt();
|
||||
container->percent = o["percent"].asFloat();
|
||||
container->rect = parse_rect_from_json(o["rect"]);
|
||||
container->window_rect = parse_rect_from_json(o["window_rect"]);
|
||||
container->deco_rect = parse_rect_from_json(o["deco_rect"]);
|
||||
container->geometry = parse_rect_from_json(o["geometry"]);
|
||||
container->urgent = o["urgent"].asBool();
|
||||
container->focused = o["focused"].asBool();
|
||||
|
||||
container->border = BorderStyle::UNKNOWN;
|
||||
std::string border = o["border"].asString();
|
||||
if (border == "normal") {
|
||||
container->border = BorderStyle::NORMAL;
|
||||
} else if (border == "none") {
|
||||
container->border = BorderStyle::NONE;
|
||||
} else if (border == "1pixel") {
|
||||
container->border = BorderStyle::ONE_PIXEL;
|
||||
} else {
|
||||
container->border_raw = border;
|
||||
I3IPC_WARN("Got a unknown \"border\" property: \"" << border << "\". Perhaps its neccessary to update i3ipc++. If you are using latest, note maintainer about this")
|
||||
}
|
||||
|
||||
container->layout = ContainerLayout::UNKNOWN;
|
||||
std::string layout = o["layout"].asString();
|
||||
|
||||
if (layout == "splith") {
|
||||
container->layout = ContainerLayout::SPLIT_H;
|
||||
} else if (layout == "splitv") {
|
||||
container->layout = ContainerLayout::SPLIT_V;
|
||||
} else if (layout == "stacked") {
|
||||
container->layout = ContainerLayout::STACKED;
|
||||
} else if (layout == "tabbed") {
|
||||
container->layout = ContainerLayout::TABBED;
|
||||
} else if (layout == "dockarea") {
|
||||
container->layout = ContainerLayout::DOCKAREA;
|
||||
} else if (layout == "output") {
|
||||
container->layout = ContainerLayout::OUTPUT;
|
||||
} else {
|
||||
container->layout_raw = border;
|
||||
I3IPC_WARN("Got a unknown \"layout\" property: \"" << layout << "\". Perhaps its neccessary to update i3ipc++. If you are using latest, note maintainer about this")
|
||||
}
|
||||
|
||||
Json::Value nodes = o["nodes"];
|
||||
if (!nodes.isNull()) {
|
||||
IPC_JSON_ASSERT_TYPE_ARRAY(nodes, "nodes")
|
||||
for (Json::ArrayIndex i = 0; i < nodes.size(); i++) {
|
||||
container->nodes.push_back(parse_container_from_json(nodes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return container;
|
||||
#undef i3IPC_TYPE_STR
|
||||
}
|
||||
|
||||
static std::shared_ptr<workspace_t> parse_workspace_from_json(const Json::Value& value) {
|
||||
if (value.isNull())
|
||||
return std::shared_ptr<workspace_t>();
|
||||
Json::Value num = value["num"];
|
||||
Json::Value name = value["name"];
|
||||
Json::Value visible = value["visible"];
|
||||
Json::Value focused = value["focused"];
|
||||
Json::Value urgent = value["urgent"];
|
||||
Json::Value rect = value["rect"];
|
||||
Json::Value output = value["output"];
|
||||
|
||||
std::shared_ptr<workspace_t> p (new workspace_t());
|
||||
p->num = num.asInt();
|
||||
p->name = name.asString();
|
||||
p->visible = visible.asBool();
|
||||
p->focused = focused.asBool();
|
||||
p->urgent = urgent.asBool();
|
||||
p->rect = parse_rect_from_json(rect);
|
||||
p->output = output.asString();
|
||||
return p;
|
||||
}
|
||||
|
||||
static std::shared_ptr<output_t> parse_output_from_json(const Json::Value& value) {
|
||||
if (value.isNull())
|
||||
return std::shared_ptr<output_t>();
|
||||
Json::Value name = value["name"];
|
||||
Json::Value active = value["active"];
|
||||
Json::Value current_workspace = value["current_workspace"];
|
||||
Json::Value rect = value["rect"];
|
||||
|
||||
std::shared_ptr<output_t> p (new output_t());
|
||||
p->name = name.asString();
|
||||
p->active = active.asBool();
|
||||
p->current_workspace = (current_workspace.isNull() ? std::string() : current_workspace.asString());
|
||||
p->rect = parse_rect_from_json(rect);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
std::string get_socketpath() {
|
||||
std::string str;
|
||||
{
|
||||
@@ -74,35 +178,40 @@ std::string get_socketpath() {
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
I3Connection::I3Connection(const std::string& socket_path) : m_main_socket(i3_connect(socket_path)), m_event_socket(-1), m_subscriptions(0), m_socket_path(socket_path) {
|
||||
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) {
|
||||
#define i3IPC_TYPE_STR "i3's event"
|
||||
signal_event.connect([this](EventType event_type, const std::shared_ptr<const buf_t>& buf) {
|
||||
switch (event_type) {
|
||||
case ET_WORKSPACE: {
|
||||
workspace_event_t ev;
|
||||
Json::Value root;
|
||||
IPC_JSON_READ(root);
|
||||
#ifdef I3IPCpp_USE_FULL_SIGNALS
|
||||
signal_workspace_event.emit(root);
|
||||
#else
|
||||
WorkspaceEventType type;
|
||||
std::string change = root["change"].asString();
|
||||
if (change == "focus") {
|
||||
type = WorkspaceEventType::FOCUS;
|
||||
ev.type = WorkspaceEventType::FOCUS;
|
||||
} else if (change == "init") {
|
||||
type = WorkspaceEventType::INIT;
|
||||
ev.type = WorkspaceEventType::INIT;
|
||||
} else if (change == "empty") {
|
||||
type = WorkspaceEventType::EMPTY;
|
||||
ev.type = WorkspaceEventType::EMPTY;
|
||||
} else if (change == "urgent") {
|
||||
type = WorkspaceEventType::URGENT;
|
||||
ev.type = WorkspaceEventType::URGENT;
|
||||
} else {
|
||||
I3IPC_WARN("Unknown workspace event type " << change)
|
||||
break;
|
||||
}
|
||||
I3IPC_DEBUG("WORKSPACE " << change)
|
||||
|
||||
signal_workspace_event.emit(type);
|
||||
#endif
|
||||
Json::Value current = root["current"];
|
||||
Json::Value old = root["current"];
|
||||
|
||||
if (!current.isNull()) {
|
||||
ev.current = parse_workspace_from_json(current);
|
||||
}
|
||||
if (!old.isNull()) {
|
||||
ev.old = parse_workspace_from_json(old);
|
||||
}
|
||||
|
||||
signal_workspace_event.emit(ev);
|
||||
break;
|
||||
}
|
||||
case ET_OUTPUT:
|
||||
@@ -114,34 +223,35 @@ I3Connection::I3Connection(const std::string& socket_path) : m_main_socket(i3_c
|
||||
signal_mode_event.emit();
|
||||
break;
|
||||
case ET_WINDOW: {
|
||||
window_event_t ev;
|
||||
Json::Value root;
|
||||
IPC_JSON_READ(root);
|
||||
#ifdef I3IPCpp_USE_FULL_SIGNALS
|
||||
signal_window_event.emit(root);
|
||||
#else
|
||||
WindowEventType type;
|
||||
std::string change = root["change"].asString();
|
||||
if (change == "new") {
|
||||
type = WindowEventType::NEW;
|
||||
ev.type = WindowEventType::NEW;
|
||||
} else if (change == "close") {
|
||||
type = WindowEventType::CLOSE;
|
||||
ev.type = WindowEventType::CLOSE;
|
||||
} else if (change == "focus") {
|
||||
type = WindowEventType::FOCUS;
|
||||
ev.type = WindowEventType::FOCUS;
|
||||
} else if (change == "title") {
|
||||
type = WindowEventType::TITLE;
|
||||
ev.type = WindowEventType::TITLE;
|
||||
} else if (change == "fullscreen_mode") {
|
||||
type = WindowEventType::FULLSCREEN_MODE;
|
||||
ev.type = WindowEventType::FULLSCREEN_MODE;
|
||||
} else if (change == "move") {
|
||||
type = WindowEventType::MOVE;
|
||||
ev.type = WindowEventType::MOVE;
|
||||
} else if (change == "floating") {
|
||||
type = WindowEventType::FLOATING;
|
||||
ev.type = WindowEventType::FLOATING;
|
||||
} else if (change == "urgent") {
|
||||
type = WindowEventType::URGENT;
|
||||
ev.type = WindowEventType::URGENT;
|
||||
}
|
||||
I3IPC_DEBUG("WINDOW " << change)
|
||||
|
||||
signal_window_event.emit(type);
|
||||
#endif
|
||||
Json::Value container = root["container"];
|
||||
if (!container.isNull()) {
|
||||
ev.container = parse_container_from_json(container);
|
||||
}
|
||||
|
||||
signal_window_event.emit(ev);
|
||||
break;
|
||||
}
|
||||
case ET_BARCONFIG_UPDATE:
|
||||
@@ -152,18 +262,18 @@ I3Connection::I3Connection(const std::string& socket_path) : m_main_socket(i3_c
|
||||
});
|
||||
#undef i3IPC_TYPE_STR
|
||||
}
|
||||
I3Connection::~I3Connection() {
|
||||
connection::~connection() {
|
||||
i3_disconnect(m_main_socket);
|
||||
if (m_event_socket > 0)
|
||||
i3_disconnect(m_event_socket);
|
||||
}
|
||||
|
||||
|
||||
void I3Connection::prepare_to_event_handling() {
|
||||
void connection::prepare_to_event_handling() {
|
||||
m_event_socket = i3_connect(m_socket_path);
|
||||
this->subscribe(m_subscriptions);
|
||||
}
|
||||
void I3Connection::handle_event() {
|
||||
void connection::handle_event() {
|
||||
if (m_event_socket <= 0) {
|
||||
throw std::runtime_error("event_socket_fd <= 0");
|
||||
}
|
||||
@@ -173,7 +283,7 @@ void I3Connection::handle_event() {
|
||||
}
|
||||
|
||||
|
||||
bool I3Connection::subscribe(const int32_t events) {
|
||||
bool connection::subscribe(const int32_t events) {
|
||||
#define i3IPC_TYPE_STR "SUBSCRIBE"
|
||||
if (m_event_socket <= 0) {
|
||||
m_subscriptions |= events;
|
||||
@@ -216,7 +326,7 @@ bool I3Connection::subscribe(const int32_t events) {
|
||||
}
|
||||
|
||||
|
||||
version_t I3Connection::get_version() const {
|
||||
version_t connection::get_version() const {
|
||||
#define i3IPC_TYPE_STR "GET_VERSION"
|
||||
auto buf = i3_msg(m_main_socket, ClientMessageType::GET_VERSION);
|
||||
Json::Value root;
|
||||
@@ -234,27 +344,27 @@ version_t I3Connection::get_version() const {
|
||||
}
|
||||
|
||||
|
||||
std::vector<output_t> I3Connection::get_outputs() const {
|
||||
std::shared_ptr<container_t> connection::get_tree() const {
|
||||
#define i3IPC_TYPE_STR "GET_TREE"
|
||||
auto buf = i3_msg(m_main_socket, ClientMessageType::GET_TREE);
|
||||
Json::Value root;
|
||||
IPC_JSON_READ(root);
|
||||
return parse_container_from_json(root);
|
||||
#undef i3IPC_TYPE_STR
|
||||
}
|
||||
|
||||
|
||||
std::vector< std::shared_ptr<output_t> > connection::get_outputs() const {
|
||||
#define i3IPC_TYPE_STR "GET_OUTPUTS"
|
||||
auto buf = i3_msg(m_main_socket, ClientMessageType::GET_OUTPUTS);
|
||||
Json::Value root;
|
||||
IPC_JSON_READ(root)
|
||||
IPC_JSON_ASSERT_TYPE_ARRAY(root, "root")
|
||||
|
||||
std::vector<output_t> outputs;
|
||||
std::vector< std::shared_ptr<output_t> > outputs;
|
||||
|
||||
for (auto w : root) {
|
||||
Json::Value name = w["name"];
|
||||
Json::Value active = w["active"];
|
||||
Json::Value current_workspace = w["current_workspace"];
|
||||
Json::Value rect = w["rect"];
|
||||
|
||||
outputs.push_back({
|
||||
.name = name.asString(),
|
||||
.active = active.asBool(),
|
||||
.current_workspace = (current_workspace.isNull() ? std::string() : current_workspace.asString()),
|
||||
.rect = parse_rect_from_json(rect),
|
||||
});
|
||||
outputs.push_back(parse_output_from_json(w));
|
||||
}
|
||||
|
||||
return outputs;
|
||||
@@ -262,33 +372,17 @@ std::vector<output_t> I3Connection::get_outputs() const {
|
||||
}
|
||||
|
||||
|
||||
std::vector<workspace_t> I3Connection::get_workspaces() const {
|
||||
std::vector< std::shared_ptr<workspace_t> > connection::get_workspaces() const {
|
||||
#define i3IPC_TYPE_STR "GET_WORKSPACES"
|
||||
auto buf = i3_msg(m_main_socket, ClientMessageType::GET_WORKSPACES);
|
||||
Json::Value root;
|
||||
IPC_JSON_READ(root)
|
||||
IPC_JSON_ASSERT_TYPE_ARRAY(root, "root")
|
||||
|
||||
std::vector<workspace_t> workspaces;
|
||||
std::vector< std::shared_ptr<workspace_t> > workspaces;
|
||||
|
||||
for (auto w : root) {
|
||||
Json::Value num = w["num"];
|
||||
Json::Value name = w["name"];
|
||||
Json::Value visible = w["visible"];
|
||||
Json::Value focused = w["focused"];
|
||||
Json::Value urgent = w["urgent"];
|
||||
Json::Value rect = w["rect"];
|
||||
Json::Value output = w["output"];
|
||||
|
||||
workspaces.push_back({
|
||||
.num = num.asInt(),
|
||||
.name = name.asString(),
|
||||
.visible = visible.asBool(),
|
||||
.focused = focused.asBool(),
|
||||
.urgent = urgent.asBool(),
|
||||
.rect = parse_rect_from_json(rect),
|
||||
.output = output.asString(),
|
||||
});
|
||||
workspaces.push_back(parse_workspace_from_json(w));
|
||||
}
|
||||
|
||||
return workspaces;
|
||||
@@ -296,7 +390,7 @@ std::vector<workspace_t> I3Connection::get_workspaces() const {
|
||||
}
|
||||
|
||||
|
||||
bool I3Connection::send_command(const std::string& command) const {
|
||||
bool connection::send_command(const std::string& command) const {
|
||||
#define i3IPC_TYPE_STR "COMMAND"
|
||||
auto buf = i3_msg(m_main_socket, ClientMessageType::COMMAND, command);
|
||||
Json::Value root;
|
||||
@@ -317,4 +411,8 @@ bool I3Connection::send_command(const std::string& command) const {
|
||||
#undef i3IPC_TYPE_STR
|
||||
}
|
||||
|
||||
int32_t connection::get_file_descriptor() {
|
||||
return m_event_socket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user