Class: I3::IPC

Inherits:
Object
  • Object
show all
Defined in:
lib/i3-ipc.rb

Defined Under Namespace

Classes: WrongMagicCode, WrongType

Constant Summary collapse

MAGIC_STRING =
"i3-ipc"
SOCKET_PATH =
"/tmp/i3-ipc.sock"
MESSAGE_TYPE_COMMAND =
0
MESSAGE_TYPE_GET_WORKSPACES =
1
MESSAGE_TYPE_SUBSCRIBE =
2
MESSAGE_REPLY_COMMAND =
0
MESSAGE_REPLY_GET_WORKSPACES =
1
MESSAGE_REPLY_SUBSCRIBE =
2
EVENT_MASK =
(1 << 31)
EVENT_WORKSPACE =
(EVENT_MASK | 0)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(socket_path = SOCKET_PATH, force_connect = false) ⇒ IPC

connects to the given i3 ipc interface

Parameters:

  • socket_path (defaults to: SOCKET_PATH)

    String the path to i3’s socket

  • force_connect (defaults to: false)

    Boolean connects to the socket if true



30
31
32
33
# File 'lib/i3-ipc.rb', line 30

def initialize(socket_path=SOCKET_PATH, force_connect=false)
  @socket_path = socket_path
  connect if connect
end

Class Method Details

.format(type, payload = nil) ⇒ Object

format the message a typical message looks like

"i3-ipc" <message length> <message type> <payload>


86
87
88
89
90
91
# File 'lib/i3-ipc.rb', line 86

def self.format(type, payload=nil)
  size = payload ? payload.to_s.bytes.count : 0
  msg = MAGIC_STRING + [size, type].pack("LL")
  msg << payload.to_s if payload
  msg
end

.parse_response(response) ⇒ Object

parse a full ipc response similar to handle_response, but parses full reply as received by EventMachine

returns an Array containing the reply type and the parsed data



103
104
105
106
107
108
109
110
111
112
# File 'lib/i3-ipc.rb', line 103

def self.parse_response(response)
  if response[0, (MAGIC_STRING.length)] != MAGIC_STRING
    raise WrongMagicCode
  end

  len, recv_type = response[6, 8].unpack("LL")

  answer = response[14, len]
  [recv_type, ::JSON.parse(answer)]
end

.subscribe(list, socket_path = SOCKET_PATH, &blk) ⇒ Object

shortcut



36
37
38
# File 'lib/i3-ipc.rb', line 36

def self.subscribe(list, socket_path=SOCKET_PATH, &blk)
  Subscription.subscribe(list, socket_path, &blk)
end

Instance Method Details

#closeObject

closes the socket connection



135
136
137
# File 'lib/i3-ipc.rb', line 135

def close
  @socket.close
end

#closed?Boolean

alias for @socket.closed? for easy access

Returns:

  • (Boolean)


140
141
142
# File 'lib/i3-ipc.rb', line 140

def closed?
  @socket.closed?
end

#command(payload) ⇒ Object

send a command to i3

the payload is a command for i3 (like the commands you can bind to keys in the configuration file) and will be executed directly after receiving it.

returns { “success” => true } for now. i3 does send this reply without checks



48
49
50
51
# File 'lib/i3-ipc.rb', line 48

def command(payload)
  write format(MESSAGE_TYPE_COMMAND, payload)
  handle_response MESSAGE_TYPE_COMMAND
end

#connectObject

connects to the given socket



130
131
132
# File 'lib/i3-ipc.rb', line 130

def connect
  @socket = UNIXSocket.new(@socket_path)
end

#format(type, payload = nil) ⇒ Object



93
94
95
# File 'lib/i3-ipc.rb', line 93

def format(type, payload=nil)
  self.class.format(type, payload)
end

#get_workspacesObject

gets the current workspaces. the reply will be the list of workspaces (see the reply section of i3 docu)



56
57
58
59
# File 'lib/i3-ipc.rb', line 56

def get_workspaces
  write format(MESSAGE_TYPE_GET_WORKSPACES)
  handle_response MESSAGE_TYPE_GET_WORKSPACES
end

#handle_response(type) ⇒ Object

reads the reply from the socket and parse the returned json into a ruby object

throws WrongMagicCode when magic word is wrong throws WrongType if returned type does not match expected

this is a bit duplicated code but I don’t know a way to read the full send reply without knowing its length

Raises:



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/i3-ipc.rb', line 70

def handle_response(type)
  # reads 14 bytes
  # length of "i3-ipc" + 4 bytes length + 4 bytes type
  buffer = read 14
  raise WrongMagicCode unless buffer[0, (MAGIC_STRING.length)] == MAGIC_STRING

  len, recv_type = buffer[6..-1].unpack("LL")
  raise WrongType unless recv_type == type

  answer = read len
  ::JSON.parse(answer)
end

#parse_response(response) ⇒ Object



114
115
116
# File 'lib/i3-ipc.rb', line 114

def parse_response(response)
  self.class.parse_response(response)
end

#read(len) ⇒ Object



125
126
127
# File 'lib/i3-ipc.rb', line 125

def read(len)
  @socket.read(len)
end

#write(msg) ⇒ Object

writes message to the socket if socket is not connected, it connects first



120
121
122
123
# File 'lib/i3-ipc.rb', line 120

def write(msg)
  connect if @socket.nil? || closed?
  @last_write_length = @socket.write msg
end