1 #include "tickit.h"
2 #include "taplib.h"
3 #include "taplib-mockterm.h"
4 
5 #include <string.h>
6 
7 struct LastEvent {
8   int type;
9   int mod;
10   int line, col, button;
11   char str[16];
12 
13   int ret;
14 };
15 
on_key_event_capture(TickitWindow * win,TickitEventFlags flags,void * _info,void * data)16 int on_key_event_capture(TickitWindow *win, TickitEventFlags flags, void *_info, void *data)
17 {
18   struct LastEvent *last_event = data;
19   TickitKeyEventInfo *info = _info;
20 
21   last_event->type = info->type;
22   last_event->mod = info->mod;
23   strcpy(last_event->str, info->str);
24 
25   return last_event->ret;
26 }
27 
on_mouse_event_capture(TickitWindow * win,TickitEventFlags flags,void * _info,void * data)28 int on_mouse_event_capture(TickitWindow *win, TickitEventFlags flags, void *_info, void *data)
29 {
30   struct LastEvent *last_event = data;
31   TickitMouseEventInfo *info = _info;
32 
33   last_event->type = info->type;
34   last_event->mod = info->mod;
35   last_event->line = info->line;
36   last_event->col = info->col;
37   last_event->button = info->button;
38 
39   return last_event->ret;
40 }
41 
42 int next_idx = 0;
43 char *ids[3];
44 
on_event_push(TickitWindow * win,TickitEventFlags flags,void * _info,void * data)45 int on_event_push(TickitWindow *win, TickitEventFlags flags, void *_info, void *data)
46 {
47   ids[next_idx++] = data;
48   return 0;
49 }
50 
on_event_incr_int(TickitWindow * win,TickitEventFlags flags,void * _info,void * data)51 int on_event_incr_int(TickitWindow *win, TickitEventFlags flags, void *_info, void *data)
52 {
53   ((int *)data)[0]++;
54   return 0;
55 }
56 
on_termevent_incr_int(TickitTerm * tt,TickitEventFlags flags,void * _info,void * data)57 int on_termevent_incr_int(TickitTerm *tt, TickitEventFlags flags, void *_info, void *data)
58 {
59   ((int *)data)[0]++;
60   return 0;
61 }
62 
63 TickitWindow *childwin = NULL;
64 int childmouse = 0;
65 
win_on_mouse_child(TickitWindow * win,TickitEventFlags flags,void * _info,void * data)66 int win_on_mouse_child(TickitWindow *win, TickitEventFlags flags, void *_info, void *data) {
67   if(childwin)
68     return 0;
69 
70   childwin = tickit_window_new(win, (TickitRect){0, 0, 2, 2}, 0);
71   tickit_window_bind_event(childwin, TICKIT_WINDOW_ON_MOUSE, 0, &on_event_incr_int, &childmouse);
72   return 0;
73 }
74 
75 TickitWindow *siblingwin = NULL;
76 int siblingmouse = 0;
77 
win_on_mouse_sibling(TickitWindow * win,TickitEventFlags flags,void * _info,void * data)78 int win_on_mouse_sibling(TickitWindow *win, TickitEventFlags flags, void *_info, void *data) {
79   if(siblingwin)
80     return 0;
81 
82   siblingwin = tickit_window_new(win, (TickitRect){0, 0, 2, 2}, 0);
83   tickit_window_bind_event(siblingwin, TICKIT_WINDOW_ON_MOUSE, 0, &on_event_incr_int, &siblingmouse);
84   return 0;
85 }
86 
main(int argc,char * argv[])87 int main(int argc, char *argv[])
88 {
89   TickitTerm *tt = make_term(25, 80);
90   TickitWindow *root = tickit_window_new_root(tt);
91 
92   TickitWindow *win = tickit_window_new(root, (TickitRect){3, 10, 4, 20}, 0);
93 
94   tickit_window_take_focus(win);
95   tickit_window_flush(root);
96 
97   struct LastEvent win_last = { .ret = 1 };
98   int key_bind_id = tickit_window_bind_event(win, TICKIT_WINDOW_ON_KEY, 0,
99       &on_key_event_capture, &win_last);
100   int mouse_bind_id = tickit_window_bind_event(win, TICKIT_WINDOW_ON_MOUSE, 0,
101       &on_mouse_event_capture, &win_last);
102 
103   // Key events
104   {
105     press_key(TICKIT_KEYEV_TEXT, "A", 0);
106 
107     is_int(win_last.type, TICKIT_KEYEV_TEXT, "win_last.type for A");
108     is_str(win_last.str,  "A",               "win_last.str for A");
109 
110     press_key(TICKIT_KEYEV_KEY, "C-a", TICKIT_MOD_CTRL);
111 
112     is_int(win_last.type, TICKIT_KEYEV_KEY, "win_last.type for C-a");
113     is_str(win_last.str,  "C-a",            "win_last.str for C-a");
114     is_int(win_last.mod,  TICKIT_MOD_CTRL,  "win_last.mod for C-a");
115   }
116 
117   // Mouse events
118   {
119     win_last.type = 0;
120     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 5, 15, 0);
121 
122     is_int(win_last.type, TICKIT_MOUSEEV_PRESS, "win_last.type for press 1@15,5");
123     is_int(win_last.line, 2,                    "win_last.line for press 1@15,5");
124     is_int(win_last.col,  5,                    "win_last.col for press 1@15,5");
125 
126     win_last.type = 0;
127     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 1, 2, 0);
128 
129     is_int(win_last.type, 0, "win_last.type still 0 after press @1,2");
130   }
131 
132   // Unhandled events are not consumed
133   {
134     int term_invoked = 0;
135     int bind_id = tickit_term_bind_event(tt, TICKIT_TERM_ON_KEY, 0, &on_termevent_incr_int, &term_invoked);
136 
137     win_last.ret = 0;
138 
139     press_key(TICKIT_KEYEV_KEY, "A", 0);
140 
141     ok(term_invoked, "term event handler invoked after unhandled window event");
142 
143     tickit_term_unbind_event_id(tt, bind_id);
144   }
145 
146   TickitWindow *subwin = tickit_window_new(win, (TickitRect){2, 2, 1, 10}, 0);
147 
148   // Subwindow
149   {
150     tickit_window_take_focus(subwin);
151     tickit_window_flush(root);
152 
153     struct LastEvent subwin_last = { .ret = 1 };
154     int sub_key_bind_id = tickit_window_bind_event(subwin, TICKIT_WINDOW_ON_KEY, 0,
155         &on_key_event_capture, &subwin_last);
156     int sub_mouse_bind_id = tickit_window_bind_event(subwin, TICKIT_WINDOW_ON_MOUSE, 0,
157         &on_mouse_event_capture, &subwin_last);
158 
159     win_last.type = 0;
160 
161     press_key(TICKIT_KEYEV_TEXT, "B", 0);
162 
163     is_int(subwin_last.type, TICKIT_KEYEV_TEXT, "subwin_last.type for B");
164     is_str(subwin_last.str,  "B",               "subwin_last.str for B");
165 
166     is_int(win_last.type, 0, "win_last.type for B");
167 
168     subwin_last.type = 0;
169 
170     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 5, 15, 0);
171 
172     is_int(subwin_last.type, TICKIT_MOUSEEV_PRESS, "subwin_last.type for press 1@15,5");
173     is_int(subwin_last.line, 0,                    "subwin_last.line for press 1@15,5");
174     is_int(subwin_last.col,  3,                    "subwin_last.col for press 1@15,5");
175 
176     subwin_last.ret = 0;
177 
178     subwin_last.type = 0;
179     win_last.type = 0;
180 
181     press_key(TICKIT_KEYEV_TEXT, "C", 0);
182 
183     is_int(subwin_last.type, TICKIT_KEYEV_TEXT, "subwin_last.type for C");
184     is_str(subwin_last.str,  "C",               "subwin_last.str for C");
185 
186     is_int(win_last.type, TICKIT_KEYEV_TEXT, "win_last.type for C");
187     is_str(win_last.str,  "C",               "win_last.str for C");
188 
189     tickit_window_unbind_event_id(subwin, sub_key_bind_id);
190     tickit_window_unbind_event_id(subwin, sub_mouse_bind_id);
191   }
192 
193   tickit_window_unbind_event_id(win, key_bind_id);
194   tickit_window_unbind_event_id(win, mouse_bind_id);
195 
196   // Event ordering
197   {
198     TickitWindow *otherwin = tickit_window_new(root, (TickitRect){10, 10, 4, 20}, 0);
199     tickit_window_flush(root);
200 
201     int bind_ids[] = {
202       tickit_window_bind_event(win,      TICKIT_WINDOW_ON_KEY, 0, &on_event_push, "win"),
203       tickit_window_bind_event(subwin,   TICKIT_WINDOW_ON_KEY, 0, &on_event_push, "subwin"),
204       tickit_window_bind_event(otherwin, TICKIT_WINDOW_ON_KEY, 0, &on_event_push, "otherwin"),
205     };
206 
207     press_key(TICKIT_KEYEV_TEXT, "D", 0);
208 
209     is_int(next_idx, 3, "press_key pushes 3 strings for D");
210     is_str(ids[0], "subwin",   "ids[0] for D");
211     is_str(ids[1], "win",      "ids[1] for D");
212     is_str(ids[2], "otherwin", "ids[2] for D");
213 
214     tickit_window_hide(subwin);
215 
216     next_idx = 0;
217 
218     press_key(TICKIT_KEYEV_TEXT, "E", 0);
219 
220     is_int(next_idx, 2, "press_key pushes 2 strings for E");
221     is_str(ids[0], "win",      "ids[0] for E");
222     is_str(ids[1], "otherwin", "ids[1] for E");
223 
224     tickit_window_unref(otherwin);
225     tickit_window_flush(root);
226 
227     tickit_window_unbind_event_id(win, bind_ids[0]);
228     tickit_window_unbind_event_id(subwin, bind_ids[1]);
229   }
230 
231   tickit_window_unref(subwin);
232 
233   // Windows created in input events handlers don't receive events
234   //   child windows
235   {
236     int id = tickit_window_bind_event(win, TICKIT_WINDOW_ON_MOUSE, 0, &win_on_mouse_child, NULL);
237 
238     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 3, 10, 0);
239 
240     ok(!!childwin, "child window created");
241     is_int(childmouse, 0, "child window has not yet received a mouse event");
242 
243     tickit_window_flush(root);
244 
245     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 3, 10, 0);
246 
247     is_int(childmouse, 1, "child window has now received an event after flush");
248 
249     tickit_window_unbind_event_id(win, id);
250     tickit_window_unref(childwin);
251     tickit_window_flush(root);
252   }
253 
254   //   sibling windows
255   {
256     int id = tickit_window_bind_event(win, TICKIT_WINDOW_ON_MOUSE, 0, &win_on_mouse_sibling, NULL);
257 
258     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 3, 10, 0);
259 
260     ok(!!siblingwin, "sibling window created");
261     is_int(siblingmouse, 0, "sibling window has not yet received a mouse event");
262 
263     tickit_window_flush(root);
264 
265     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 3, 10, 0);
266 
267     is_int(siblingmouse, 1, "sibling window has now received an event after flush");
268 
269     tickit_window_unbind_event_id(win, id);
270     tickit_window_unref(siblingwin);
271     tickit_window_flush(root);
272   }
273 
274   // STEAL_INPUT
275   {
276     TickitWindow *thief = tickit_window_new(root, (TickitRect){2, 5, 3, 3},
277         TICKIT_WINDOW_STEAL_INPUT);
278 
279     struct LastEvent thief_last = { .ret = 1 };
280     tickit_window_bind_event(thief, TICKIT_WINDOW_ON_KEY, 0, &on_key_event_capture, &thief_last);
281     tickit_window_bind_event(thief, TICKIT_WINDOW_ON_MOUSE, 0, &on_mouse_event_capture, &thief_last);
282 
283     ok(tickit_window_is_steal_input(thief), "tickit_window_is_steal_input() returns true");
284 
285     press_key(TICKIT_KEYEV_TEXT, "D", 0);
286 
287     is_int(thief_last.type, TICKIT_KEYEV_TEXT, "thief_last.type for D");
288     is_str(thief_last.str, "D",                "thief_last.str for D");
289 
290     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 1, 1, 0);
291 
292     is_int(thief_last.type, TICKIT_MOUSEEV_PRESS, "thief_last.type for press 1@1,1");
293     is_int(thief_last.line, -1,                   "thief_last.line for press 1@1,1");
294     is_int(thief_last.col,  -4,                   "thief_last.col for press 1@1,1");
295 
296     thief_last.type = 0;
297     win_last.type = 0;
298 
299     tickit_window_setctl_int(thief, TICKIT_WINCTL_STEAL_INPUT, false);
300     ok(!tickit_window_is_steal_input(thief), "tickit_window_is_steal_input() returns false");
301 
302     press_mouse(TICKIT_MOUSEEV_PRESS, 1, 1, 1, 0);
303 
304     is_int(thief_last.type, 0, "thief does not see event after disabling STEAL_INPUT");
305 
306     tickit_window_unref(thief);
307   }
308 
309   tickit_window_unref(win);
310   tickit_window_unref(root);
311   tickit_term_unref(tt);
312 
313   return exit_status();
314 }
315