Skip to main content

i3ipc/
event.rs

1//! Abstractions for the events passed back from i3.
2
3use common;
4use reply;
5use serde_json as json;
6use std::str::FromStr;
7
8use event::inner::*;
9
10/// An event passed back from i3.
11#[derive(Debug)]
12pub enum Event {
13    WorkspaceEvent(WorkspaceEventInfo),
14    OutputEvent(OutputEventInfo),
15    ModeEvent(ModeEventInfo),
16    WindowEvent(WindowEventInfo),
17    BarConfigEvent(BarConfigEventInfo),
18    BindingEvent(BindingEventInfo),
19
20    #[cfg(feature = "i3-4-14")]
21    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
22    ShutdownEvent(ShutdownEventInfo),
23}
24
25/// Data for `WorkspaceEvent`.
26#[derive(Debug)]
27pub struct WorkspaceEventInfo {
28    /// The type of change.
29    pub change: WorkspaceChange,
30    /// Will be `Some` if the type of event affects the workspace.
31    pub current: Option<reply::Node>,
32    /// Will be `Some` only when `change == Focus` *and* there was a previous workspace.
33    /// Note that if the previous workspace was empty it will get destroyed when switching, but
34    /// will still appear here.
35    pub old: Option<reply::Node>,
36}
37
38impl FromStr for WorkspaceEventInfo {
39    type Err = json::error::Error;
40    fn from_str(s: &str) -> Result<Self, Self::Err> {
41        let val: json::Value = try!(json::from_str(s));
42        Ok(WorkspaceEventInfo {
43            change: match val.get("change").unwrap().as_str().unwrap() {
44                "focus" => WorkspaceChange::Focus,
45                "init" => WorkspaceChange::Init,
46                "empty" => WorkspaceChange::Empty,
47                "urgent" => WorkspaceChange::Urgent,
48                "rename" => WorkspaceChange::Rename,
49                "reload" => WorkspaceChange::Reload,
50                "move" => WorkspaceChange::Move,
51                "restored" => WorkspaceChange::Restored,
52                other => {
53                    warn!(target: "i3ipc", "Unknown WorkspaceChange {}", other);
54                    WorkspaceChange::Unknown
55                }
56            },
57            current: match val.get("current").unwrap().clone() {
58                json::Value::Null => None,
59                val => Some(common::build_tree(&val)),
60            },
61            old: match val.get("old") {
62                Some(o) => match o.clone() {
63                    json::Value::Null => None,
64                    val => Some(common::build_tree(&val)),
65                },
66                None => None,
67            },
68        })
69    }
70}
71
72/// Data for `OutputEvent`.
73#[derive(Debug)]
74pub struct OutputEventInfo {
75    /// The type of change.
76    pub change: OutputChange,
77}
78
79impl FromStr for OutputEventInfo {
80    type Err = json::error::Error;
81    fn from_str(s: &str) -> Result<Self, Self::Err> {
82        let val: json::Value = try!(json::from_str(s));
83        Ok(OutputEventInfo {
84            change: match val.get("change").unwrap().as_str().unwrap() {
85                "unspecified" => OutputChange::Unspecified,
86                other => {
87                    warn!(target: "i3ipc", "Unknown OutputChange {}", other);
88                    OutputChange::Unknown
89                }
90            },
91        })
92    }
93}
94
95/// Data for `ModeEvent`.
96#[derive(Debug)]
97pub struct ModeEventInfo {
98    /// The name of current mode in use. It is the same as specified in config when creating a
99    /// mode. The default mode is simply named default.
100    pub change: String,
101}
102
103impl FromStr for ModeEventInfo {
104    type Err = json::error::Error;
105    fn from_str(s: &str) -> Result<Self, Self::Err> {
106        let val: json::Value = try!(json::from_str(s));
107        Ok(ModeEventInfo {
108            change: val.get("change").unwrap().as_str().unwrap().to_owned(),
109        })
110    }
111}
112
113/// Data for `WindowEvent`.
114#[derive(Debug)]
115pub struct WindowEventInfo {
116    /// Indicates the type of change
117    pub change: WindowChange,
118    /// The window's parent container. Be aware that for the "new" event, the container will hold
119    /// the initial name of the newly reparented window (e.g. if you run urxvt with a shell that
120    /// changes the title, you will still at this point get the window title as "urxvt").
121    pub container: reply::Node,
122}
123
124impl FromStr for WindowEventInfo {
125    type Err = json::error::Error;
126    fn from_str(s: &str) -> Result<Self, Self::Err> {
127        let val: json::Value = try!(json::from_str(s));
128        Ok(WindowEventInfo {
129            change: match val.get("change").unwrap().as_str().unwrap() {
130                "new" => WindowChange::New,
131                "close" => WindowChange::Close,
132                "focus" => WindowChange::Focus,
133                "title" => WindowChange::Title,
134                "fullscreen_mode" => WindowChange::FullscreenMode,
135                "move" => WindowChange::Move,
136                "floating" => WindowChange::Floating,
137                "urgent" => WindowChange::Urgent,
138
139                #[cfg(feature = "i3-4-13")]
140                "mark" => WindowChange::Mark,
141
142                other => {
143                    warn!(target: "i3ipc", "Unknown WindowChange {}", other);
144                    WindowChange::Unknown
145                }
146            },
147            container: common::build_tree(val.get("container").unwrap()),
148        })
149    }
150}
151
152/// Data for `BarConfigEvent`.
153#[derive(Debug)]
154pub struct BarConfigEventInfo {
155    /// The new i3 bar configuration.
156    pub bar_config: reply::BarConfig,
157}
158
159impl FromStr for BarConfigEventInfo {
160    type Err = json::error::Error;
161    fn from_str(s: &str) -> Result<Self, Self::Err> {
162        let val: json::Value = try!(json::from_str(s));
163        Ok(BarConfigEventInfo {
164            bar_config: common::build_bar_config(&val),
165        })
166    }
167}
168
169/// Data for `BindingEvent`.
170///
171/// Reports on the details of a binding that ran a command because of user input.
172#[derive(Debug)]
173pub struct BindingEventInfo {
174    /// Indicates what sort of binding event was triggered (right now it will always be "run" but
175    /// that may be expanded in the future).
176    pub change: BindingChange,
177    pub binding: Binding,
178}
179
180impl FromStr for BindingEventInfo {
181    type Err = json::error::Error;
182    fn from_str(s: &str) -> Result<Self, Self::Err> {
183        let val: json::Value = try!(json::from_str(s));
184        let bind = val.get("binding").unwrap();
185        Ok(BindingEventInfo {
186            change: match val.get("change").unwrap().as_str().unwrap() {
187                "run" => BindingChange::Run,
188                other => {
189                    warn!(target: "i3ipc", "Unknown BindingChange {}", other);
190                    BindingChange::Unknown
191                }
192            },
193            binding: Binding {
194                command: bind.get("command").unwrap().as_str().unwrap().to_owned(),
195                event_state_mask: bind
196                    .get("event_state_mask")
197                    .unwrap()
198                    .as_array()
199                    .unwrap()
200                    .iter()
201                    .map(|m| m.as_str().unwrap().to_owned())
202                    .collect(),
203                input_code: bind.get("input_code").unwrap().as_i64().unwrap() as i32,
204                symbol: match bind.get("symbol").unwrap().clone() {
205                    json::Value::String(s) => Some(s),
206                    json::Value::Null => None,
207                    _ => unreachable!(),
208                },
209                input_type: match bind.get("input_type").unwrap().as_str().unwrap() {
210                    "keyboard" => InputType::Keyboard,
211                    "mouse" => InputType::Mouse,
212                    other => {
213                        warn!(target: "i3ipc", "Unknown InputType {}", other);
214                        InputType::Unknown
215                    }
216                },
217            },
218        })
219    }
220}
221
222/// Data for `ShutdownEvent`.
223#[derive(Debug)]
224#[cfg(feature = "i3-4-14")]
225#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
226pub struct ShutdownEventInfo {
227    pub change: ShutdownChange,
228}
229
230#[cfg(feature = "i3-4-14")]
231#[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
232impl FromStr for ShutdownEventInfo {
233    type Err = json::error::Error;
234    fn from_str(s: &str) -> Result<Self, Self::Err> {
235        let val: json::Value = try!(json::from_str(s));
236        let change = match val.get("change").unwrap().as_str().unwrap() {
237            "restart" => ShutdownChange::Restart,
238            "exit" => ShutdownChange::Exit,
239            other => {
240                warn!(target: "i3ipc", "Unknown ShutdownChange {}", other);
241                ShutdownChange::Unknown
242            }
243        };
244        Ok(ShutdownEventInfo { change })
245    }
246}
247
248/// Less important types
249pub mod inner {
250    /// The kind of workspace change.
251    #[derive(Debug, PartialEq)]
252    pub enum WorkspaceChange {
253        Focus,
254        Init,
255        Empty,
256        Urgent,
257        Rename,
258        Reload,
259        Restored,
260        Move,
261        /// A WorkspaceChange we don't support yet.
262        Unknown,
263    }
264
265    /// The kind of output change.
266    #[derive(Debug, PartialEq)]
267    pub enum OutputChange {
268        Unspecified,
269        /// An OutputChange we don't support yet.
270        Unknown,
271    }
272
273    /// The kind of window change.
274    #[derive(Debug, PartialEq)]
275    pub enum WindowChange {
276        /// The window has become managed by i3.
277        New,
278        /// The window has closed>.
279        Close,
280        /// The window has received input focus.
281        Focus,
282        /// The window's title has changed.
283        Title,
284        /// The window has entered or exited fullscreen mode.
285        FullscreenMode,
286        /// The window has changed its position in the tree.
287        Move,
288        /// The window has transitioned to or from floating.
289        Floating,
290        /// The window has become urgent or lost its urgent status.
291        Urgent,
292
293        /// A mark has been added to or removed from the window.
294        #[cfg(feature = "i3-4-13")]
295        #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-13")))]
296        Mark,
297
298        /// A WindowChange we don't support yet.
299        Unknown,
300    }
301
302    /// Either keyboard or mouse.
303    #[derive(Debug, PartialEq)]
304    pub enum InputType {
305        Keyboard,
306        Mouse,
307        /// An InputType we don't support yet.
308        Unknown,
309    }
310
311    /// Contains details about the binding that was run.
312    #[derive(Debug, PartialEq)]
313    pub struct Binding {
314        /// The i3 command that is configured to run for this binding.
315        pub command: String,
316
317        /// The group and modifier keys that were configured with this binding.
318        pub event_state_mask: Vec<String>,
319
320        /// If the binding was configured with blindcode, this will be the key code that was given for
321        /// the binding. If the binding is a mouse binding, it will be the number of times the mouse
322        /// button was pressed. Otherwise it will be 0.
323        pub input_code: i32,
324
325        /// If this is a keyboard binding that was configured with bindsym, this field will contain the
326        /// given symbol. Otherwise it will be None.
327        pub symbol: Option<String>,
328
329        /// Will be Keyboard or Mouse depending on whether this was a keyboard or mouse binding.
330        pub input_type: InputType,
331    }
332
333    /// The kind of binding change.
334    #[derive(Debug, PartialEq)]
335    pub enum BindingChange {
336        Run,
337        /// A BindingChange we don't support yet.
338        Unknown,
339    }
340
341    /// The kind of shutdown change.
342    #[derive(Debug, PartialEq)]
343    #[cfg(feature = "i3-4-14")]
344    #[cfg_attr(feature = "dox", doc(cfg(feature = "i3-4-14")))]
345    pub enum ShutdownChange {
346        Restart,
347        Exit,
348        /// A ShutdownChange we don't support yet.
349        Unknown,
350    }
351}