Implement the ipc 'binding' event
Patch status: needinfo
Patch by Tony Crisci
Long description:
The binding event will be triggered when a binding is run as a result of some a user action. The binding event has the following properties: change: (str) Currently this will only be "run" but may be expanded in the future. Included for consistency with other events. binding: (map) the serialized binding The "binding" member will have these properties: input_type: (str) either "keyboard" or "mouse" input_code: (int) the xcb keycode of the keyboard binding if it was provided or the mouse button if it is a mouse binding. symbol: (str) the string representation of the input code command: (str) the bound command mods: (list of str) a list of the modifiers that were pressed as string symbols fixes #1210
To apply this patch, use:
curl http://cr.i3wm.org/patch/508/raw.patch | git am
b/include/bindings.h
41 |
@@ -48,3 +48,8 @@ void translate_keysyms(void); |
42 |
* |
43 |
*/ |
44 |
void switch_mode(const char *new_mode); |
45 |
+ |
46 |
+/** |
47 |
+ * Runs the given binding and returns a CommandResult |
48 |
+ */ |
49 |
+struct CommandResult *run_binding(Binding *bind); |
b/include/i3/ipc.h
54 |
@@ -100,3 +100,6 @@ typedef struct i3_ipc_header { |
55 |
|
56 |
/** Bar config update will be triggered to update the bar config */ |
57 |
#define I3_IPC_EVENT_BARCONFIG_UPDATE (I3_IPC_EVENT_MASK | 4) |
58 |
+ |
59 |
+/** The binding event will be triggered when bindings run */ |
60 |
+#define I3_IPC_EVENT_BINDING (I3_IPC_EVENT_MASK | 5) |
b/include/ipc.h
65 |
@@ -93,3 +93,8 @@ void ipc_send_workspace_focus_event(Con *current, Con *old); |
66 |
* also the window container, in "container". |
67 |
*/ |
68 |
void ipc_send_window_event(const char *property, Con *con); |
69 |
+ |
70 |
+/** |
71 |
+ * For the binding events, we send the serialized binding struct. |
72 |
+ */ |
73 |
+void ipc_send_binding_event(const char *event_type, Binding *binding); |
b/src/bindings.c
78 |
@@ -259,3 +259,19 @@ void switch_mode(const char *new_mode) { |
79 |
|
80 |
ELOG("ERROR: Mode not found\n"); |
81 |
} |
82 |
+ |
83 |
+/* |
84 |
+ * Runs the given binding and returns a CommandResult |
85 |
+ */ |
86 |
+struct CommandResult *run_binding(Binding *bind) { |
87 |
+ char *command_copy = sstrdup(bind->command); |
88 |
+ struct CommandResult *command_output = parse_command(command_copy); |
89 |
+ free(command_copy); |
90 |
+ |
91 |
+ if (command_output->needs_tree_render) |
92 |
+ tree_render(); |
93 |
+ |
94 |
+ ipc_send_binding_event("run", bind); |
95 |
+ |
96 |
+ return command_output; |
97 |
+} |
b/src/ipc.c
102 |
@@ -147,6 +147,57 @@ static void dump_rect(yajl_gen gen, const char *name, Rect r) { |
103 |
y(map_close); |
104 |
} |
105 |
|
106 |
+static void dump_binding(yajl_gen gen, Binding *bind) { |
107 |
+ y(map_open); |
108 |
+ ystr("input_code"); |
109 |
+ y(integer, bind->keycode); |
110 |
+ |
111 |
+ ystr("input_type"); |
112 |
+ ystr((const char*)(bind->input_type == B_KEYBOARD ? "keyboard" : "mouse")); |
113 |
+ |
114 |
+ ystr("symbol"); |
115 |
+ ystr(bind->symbol); |
116 |
+ |
117 |
+ ystr("command"); |
118 |
+ ystr(bind->command); |
119 |
+ |
120 |
+ ystr("mods"); |
121 |
+ y(array_open); |
122 |
+ for (int i = 0; i < 8; i++) { |
123 |
+ if (bind->mods & (1 << i)) { |
124 |
+ switch (1 << i) { |
125 |
+ case XCB_MOD_MASK_SHIFT: |
126 |
+ ystr("Shift"); |
127 |
+ break; |
128 |
+ case XCB_MOD_MASK_LOCK: |
129 |
+ ystr("Lock"); |
130 |
+ break; |
131 |
+ case XCB_MOD_MASK_CONTROL: |
132 |
+ ystr("Control"); |
133 |
+ break; |
134 |
+ case XCB_MOD_MASK_1: |
135 |
+ ystr("Mod1"); |
136 |
+ break; |
137 |
+ case XCB_MOD_MASK_2: |
138 |
+ ystr("Mod2"); |
139 |
+ break; |
140 |
+ case XCB_MOD_MASK_3: |
141 |
+ ystr("Mod3"); |
142 |
+ break; |
143 |
+ case XCB_MOD_MASK_4: |
144 |
+ ystr("Mod4"); |
145 |
+ break; |
146 |
+ case XCB_MOD_MASK_5: |
147 |
+ ystr("Mod5"); |
148 |
+ break; |
149 |
+ } |
150 |
+ } |
151 |
+ } |
152 |
+ y(array_close); |
153 |
+ |
154 |
+ y(map_close); |
155 |
+} |
156 |
+ |
157 |
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) { |
158 |
y(map_open); |
159 |
ystr("id"); |
160 |
@@ -1090,3 +1141,33 @@ void ipc_send_window_event(const char *property, Con *con) { |
161 |
y(free); |
162 |
setlocale(LC_NUMERIC, ""); |
163 |
} |
164 |
+ |
165 |
+/* |
166 |
+ * For the binding events, we send the serialized binding struct. |
167 |
+ */ |
168 |
+void ipc_send_binding_event(const char *event_type, Binding *bind) { |
169 |
+ DLOG("Issue IPC binding %s event (sym = %s, code = %d)\n", event_type, bind->symbol, bind->keycode); |
170 |
+ |
171 |
+ setlocale(LC_NUMERIC, "C"); |
172 |
+ |
173 |
+ yajl_gen gen = ygenalloc(); |
174 |
+ |
175 |
+ y(map_open); |
176 |
+ |
177 |
+ ystr("change"); |
178 |
+ ystr(event_type); |
179 |
+ |
180 |
+ ystr("binding"); |
181 |
+ dump_binding(gen, bind); |
182 |
+ |
183 |
+ y(map_close); |
184 |
+ |
185 |
+ const unsigned char *payload; |
186 |
+ ylength length; |
187 |
+ y(get_buf, &payload, &length); |
188 |
+ |
189 |
+ ipc_send_event("binding", I3_IPC_EVENT_BINDING, (const char *)payload); |
190 |
+ |
191 |
+ y(free); |
192 |
+ setlocale(LC_NUMERIC, ""); |
193 |
+} |
b/src/key_press.c
198 |
@@ -105,12 +105,7 @@ void handle_key_press(xcb_key_press_event_t *event) { |
199 |
} |
200 |
} |
201 |
|
202 |
- char *command_copy = sstrdup(bind->command); |
203 |
- struct CommandResult *command_output = parse_command(command_copy); |
204 |
- free(command_copy); |
205 |
- |
206 |
- if (command_output->needs_tree_render) |
207 |
- tree_render(); |
208 |
+ struct CommandResult *command_output = run_binding(bind); |
209 |
|
210 |
/* We parse the JSON reply to figure out whether there was an error |
211 |
* ("success" being false in on of the returned dictionaries). */ |