-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
1,903 additions
and
250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
files | ||
build | ||
.vscode | ||
builddir |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,138 +1,138 @@ | ||
/** | ||
* A client library for i3-wm that deserializes into idomatic Vala response objects. | ||
/** | ||
* A client library for i3-wm that deserializes into idomatic Vala response objects. | ||
*/ | ||
namespace Grelier { | ||
enum I3_COMMAND { | ||
RUN_COMMAND, | ||
GET_WORKSPACES, | ||
SUBSCRIBE, | ||
GET_OUTPUTS, | ||
GET_TREE, | ||
GET_MARKS, | ||
GET_BAR_CONFIG, | ||
GET_VERSION, | ||
GET_BINDING_MODES, | ||
GET_CONFIG, | ||
SEND_TICK, | ||
SYNC | ||
} | ||
|
||
public errordomain I3_ERROR { | ||
RPC_ERROR | ||
} | ||
|
||
// https://i3wm.org/docs/ipc.html#_version_reply | ||
public class VersionReply { | ||
public string human_readable { get; private set; } | ||
public string loaded_config_file_name { get; private set; } | ||
public string minor { get; private set; } | ||
public string patch { get; private set; } | ||
public string major { get; private set; } | ||
|
||
internal VersionReply(Json.Node responseJson) { | ||
human_readable = responseJson.get_object().get_string_member("human_readable"); | ||
loaded_config_file_name = responseJson.get_object().get_string_member("loaded_config_file_name"); | ||
minor = responseJson.get_object().get_string_member("minor"); | ||
patch = responseJson.get_object().get_string_member("patch"); | ||
major = responseJson.get_object().get_string_member("major"); | ||
} | ||
} | ||
|
||
// https://i3wm.org/docs/ipc.html#_config_reply | ||
public class ConfigReply { | ||
public string config { get; private set; } | ||
|
||
internal ConfigReply(Json.Node responseJson) { | ||
config = responseJson.get_object().get_string_member("config"); | ||
} | ||
} | ||
|
||
public class Client { | ||
private Socket socket; | ||
private uint8[] magic_number = "i3-ipc".data; | ||
private uint8[] terminator = { '\0' }; | ||
private int bytes_to_payload = 14; | ||
private int buffer_size = 1024 * 128; | ||
|
||
public Client(string i3Socket) throws GLib.Error { | ||
var socketAddress = new UnixSocketAddress(i3Socket); | ||
|
||
socket = new Socket (SocketFamily.UNIX, SocketType.STREAM, SocketProtocol.DEFAULT); | ||
assert (socket != null); | ||
|
||
socket.connect (socketAddress); | ||
socket.set_blocking(true); | ||
enum I3_COMMAND { | ||
RUN_COMMAND, | ||
GET_WORKSPACES, | ||
SUBSCRIBE, | ||
GET_OUTPUTS, | ||
GET_TREE, | ||
GET_MARKS, | ||
GET_BAR_CONFIG, | ||
GET_VERSION, | ||
GET_BINDING_MODES, | ||
GET_CONFIG, | ||
SEND_TICK, | ||
SYNC | ||
} | ||
|
||
~Client() { | ||
if (socket != null) { | ||
socket.close(); | ||
} | ||
public errordomain I3_ERROR { | ||
RPC_ERROR | ||
} | ||
|
||
private uint8[] int32_to_uint8_array(int32 input) { | ||
Variant val = new Variant.int32(input); | ||
return val.get_data_as_bytes().get_data(); | ||
// https://i3wm.org/docs/ipc.html#_version_reply | ||
public class VersionReply { | ||
public string human_readable { get; private set; } | ||
public string loaded_config_file_name { get; private set; } | ||
public string minor { get; private set; } | ||
public string patch { get; private set; } | ||
public string major { get; private set; } | ||
|
||
internal VersionReply (Json.Node responseJson) { | ||
human_readable = responseJson.get_object ().get_string_member ("human_readable"); | ||
loaded_config_file_name = responseJson.get_object ().get_string_member ("loaded_config_file_name"); | ||
minor = responseJson.get_object ().get_string_member ("minor"); | ||
patch = responseJson.get_object ().get_string_member ("patch"); | ||
major = responseJson.get_object ().get_string_member ("major"); | ||
} | ||
} | ||
|
||
private string terminate_string(uint8[] rawString) { | ||
ByteArray b = new ByteArray(); | ||
b.append(rawString); | ||
b.append(terminator); | ||
// https://i3wm.org/docs/ipc.html#_config_reply | ||
public class ConfigReply { | ||
public string config { get; private set; } | ||
|
||
return (string) b.data; | ||
internal ConfigReply (Json.Node responseJson) { | ||
config = responseJson.get_object ().get_string_member ("config"); | ||
} | ||
} | ||
|
||
private uint8[] generate_request(I3_COMMAND cmd) { | ||
ByteArray np = new ByteArray(); | ||
public class Client { | ||
private Socket socket; | ||
private uint8[] magic_number = "i3-ipc".data; | ||
private uint8[] terminator = { '\0' }; | ||
private int bytes_to_payload = 14; | ||
private int buffer_size = 1024 * 128; | ||
|
||
np.append(magic_number); | ||
np.append(int32_to_uint8_array(0)); // payloadSize.get_data_as_bytes().get_data()); | ||
np.append(int32_to_uint8_array(cmd)); // command.get_data_as_bytes().get_data()); | ||
|
||
Bytes message = ByteArray.free_to_bytes(np); | ||
public Client (string i3Socket) throws GLib.Error { | ||
var socketAddress = new UnixSocketAddress (i3Socket); | ||
|
||
return message.get_data(); | ||
} | ||
socket = new Socket (SocketFamily.UNIX, SocketType.STREAM, SocketProtocol.DEFAULT); | ||
assert (socket != null); | ||
|
||
private Json.Node? i3_ipc(I3_COMMAND command) throws GLib.Error { | ||
ssize_t sent = socket.send(generate_request(command)); | ||
socket.connect (socketAddress); | ||
socket.set_blocking (true); | ||
} | ||
|
||
debug("Sent " + sent.to_string() + " bytes to i3.\n"); | ||
uint8[] buffer = new uint8[buffer_size]; | ||
~Client () { | ||
if (socket != null) { | ||
socket.close (); | ||
} | ||
} | ||
|
||
ssize_t len = socket.receive (buffer); | ||
private uint8[] int32_to_uint8_array (int32 input) { | ||
Variant val = new Variant.int32 (input); | ||
return val.get_data_as_bytes ().get_data (); | ||
} | ||
|
||
debug("Received " + len.to_string() + " bytes from i3.\n"); | ||
private string terminate_string (uint8[] rawString) { | ||
ByteArray b = new ByteArray (); | ||
b.append (rawString); | ||
b.append (terminator); | ||
|
||
Bytes responseBytes = new Bytes.take(buffer[0:len]); | ||
return (string) b.data; | ||
} | ||
|
||
string payload = terminate_string(responseBytes.slice(bytes_to_payload, responseBytes.length).get_data()); | ||
private uint8[] generate_request (I3_COMMAND cmd) { | ||
ByteArray np = new ByteArray (); | ||
|
||
Json.Parser parser = new Json.Parser(); | ||
parser.load_from_data(payload); | ||
np.append (magic_number); | ||
np.append (int32_to_uint8_array (0)); // payloadSize.get_data_as_bytes().get_data()); | ||
np.append (int32_to_uint8_array (cmd)); // command.get_data_as_bytes().get_data()); | ||
|
||
return parser.get_root(); | ||
} | ||
Bytes message = ByteArray.free_to_bytes (np); | ||
|
||
public VersionReply getVersion() throws I3_ERROR, GLib.Error { | ||
var response = i3_ipc(I3_COMMAND.GET_VERSION); | ||
return message.get_data (); | ||
} | ||
|
||
if (response == null) { | ||
throw new I3_ERROR.RPC_ERROR("No Response"); | ||
} | ||
private Json.Node ? i3_ipc (I3_COMMAND command) throws GLib.Error { | ||
ssize_t sent = socket.send (generate_request (command)); | ||
|
||
return new VersionReply(response); | ||
} | ||
debug ("Sent " + sent.to_string () + " bytes to i3.\n"); | ||
uint8[] buffer = new uint8[buffer_size]; | ||
|
||
ssize_t len = socket.receive (buffer); | ||
|
||
debug ("Received " + len.to_string () + " bytes from i3.\n"); | ||
|
||
Bytes responseBytes = new Bytes.take (buffer[0 : len]); | ||
|
||
string payload = terminate_string (responseBytes.slice (bytes_to_payload, responseBytes.length).get_data ()); | ||
|
||
Json.Parser parser = new Json.Parser (); | ||
parser.load_from_data (payload); | ||
|
||
return parser.get_root (); | ||
} | ||
|
||
public VersionReply getVersion () throws I3_ERROR, GLib.Error { | ||
var response = i3_ipc (I3_COMMAND.GET_VERSION); | ||
|
||
if (response == null) { | ||
throw new I3_ERROR.RPC_ERROR ("No Response"); | ||
} | ||
|
||
return new VersionReply (response); | ||
} | ||
|
||
public ConfigReply getConfig() throws I3_ERROR, GLib.Error { | ||
var response = i3_ipc(I3_COMMAND.GET_CONFIG); | ||
public ConfigReply getConfig () throws I3_ERROR, GLib.Error { | ||
var response = i3_ipc (I3_COMMAND.GET_CONFIG); | ||
|
||
if (response == null) { | ||
throw new I3_ERROR.RPC_ERROR("No Response"); | ||
} | ||
if (response == null) { | ||
throw new I3_ERROR.RPC_ERROR ("No Response"); | ||
} | ||
|
||
return new ConfigReply(response); | ||
return new ConfigReply (response); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.