1 #include <hikari/group_assign_mode.h>
2 
3 #include <ctype.h>
4 #include <stdbool.h>
5 #include <string.h>
6 
7 #include <wayland-util.h>
8 
9 #include <hikari/color.h>
10 #include <hikari/completion.h>
11 #include <hikari/configuration.h>
12 #include <hikari/group.h>
13 #include <hikari/indicator.h>
14 #include <hikari/indicator_frame.h>
15 #include <hikari/keyboard.h>
16 #include <hikari/memory.h>
17 #include <hikari/normal_mode.h>
18 #include <hikari/renderer.h>
19 #include <hikari/server.h>
20 #include <hikari/sheet.h>
21 #include <hikari/view.h>
22 #include <hikari/workspace.h>
23 
24 static struct hikari_group_assign_mode *
get_mode(void)25 get_mode(void)
26 {
27   struct hikari_group_assign_mode *mode = &hikari_server.group_assign_mode;
28 
29   assert(mode == (struct hikari_group_assign_mode *)hikari_server.mode);
30 
31   return mode;
32 }
33 
34 static void
init_completion(void)35 init_completion(void)
36 {
37   struct hikari_group_assign_mode *mode = get_mode();
38 
39   if (mode->completion != NULL) {
40     return;
41   }
42 
43   struct hikari_group *group;
44   struct hikari_completion *completion =
45       hikari_malloc(sizeof(struct hikari_completion));
46 
47   char *input = mode->input_buffer.buffer;
48 
49   hikari_completion_init(completion, input);
50 
51   wl_list_for_each (group, &hikari_server.groups, server_groups) {
52     char *name = group->name;
53 
54     if (strstr(name, input) == name && strcmp(name, input) != 0) {
55       hikari_completion_add(completion, name);
56     }
57   }
58 
59   mode->completion = completion;
60 }
61 
62 static void
fini_completion(void)63 fini_completion(void)
64 {
65   struct hikari_group_assign_mode *mode = get_mode();
66 
67   if (mode->completion == NULL) {
68     return;
69   }
70 
71   hikari_completion_fini(mode->completion);
72   hikari_free(mode->completion);
73   mode->completion = NULL;
74 }
75 
76 static void
put_char(struct hikari_input_buffer * input_buffer,struct hikari_keyboard * keyboard,uint32_t keycode)77 put_char(struct hikari_input_buffer *input_buffer,
78     struct hikari_keyboard *keyboard,
79     uint32_t keycode)
80 {
81   uint32_t codepoint = hikari_keyboard_get_codepoint(keyboard, keycode);
82 
83   if (codepoint) {
84     fini_completion();
85     hikari_input_buffer_add_utf32_char(input_buffer, codepoint);
86   }
87 }
88 
89 static void
confirm_group_assign(void)90 confirm_group_assign(void)
91 {
92   struct hikari_group_assign_mode *mode = get_mode();
93   struct hikari_workspace *workspace = hikari_server.workspace;
94   struct hikari_view *view = workspace->focus_view;
95   struct hikari_group *group;
96 
97   char *input = mode->input_buffer.buffer;
98   if (!strcmp(input, "")) {
99     group = hikari_server_find_or_create_group(view->id);
100   } else {
101     group = hikari_server_find_or_create_group(input);
102   }
103 
104   assert(group != NULL);
105 
106   hikari_view_group(view, group);
107 
108   hikari_server_enter_normal_mode(NULL);
109 }
110 
111 static void
update_state(void)112 update_state(void)
113 {
114   struct hikari_group_assign_mode *mode = get_mode();
115   struct hikari_workspace *workspace = hikari_server.workspace;
116   struct hikari_view *view = workspace->focus_view;
117   struct hikari_output *output = view->output;
118   struct hikari_indicator *indicator = &hikari_server.indicator;
119 
120   struct wlr_box *geometry = hikari_view_border_geometry(view);
121   char *input = mode->input_buffer.buffer;
122 
123   struct hikari_group *group = hikari_server_find_group(input);
124 
125   hikari_indicator_damage_group(indicator, output, geometry);
126 
127   if (!strcmp(input, "")) {
128     hikari_indicator_update_group(indicator, output, " ");
129   } else {
130     hikari_indicator_update_group(indicator, output, input);
131   }
132 
133   if (mode->group != group) {
134     if (mode->group != NULL) {
135       hikari_group_damage(mode->group);
136     }
137 
138     if (group != NULL) {
139       hikari_group_damage(group);
140     }
141 
142     mode->group = group;
143   }
144 
145   hikari_indicator_damage_group(indicator, output, geometry);
146 }
147 
148 static void
handle_keysym(struct hikari_keyboard * keyboard,uint32_t keycode,xkb_keysym_t sym)149 handle_keysym(
150     struct hikari_keyboard *keyboard, uint32_t keycode, xkb_keysym_t sym)
151 {
152   struct hikari_group_assign_mode *mode = get_mode();
153   struct hikari_input_buffer *input_buffer = &mode->input_buffer;
154 
155   char *text;
156 
157   switch (sym) {
158     case XKB_KEY_Caps_Lock:
159     case XKB_KEY_Shift_L:
160     case XKB_KEY_Shift_R:
161     case XKB_KEY_Control_L:
162     case XKB_KEY_Control_R:
163     case XKB_KEY_Meta_L:
164     case XKB_KEY_Meta_R:
165     case XKB_KEY_Alt_L:
166     case XKB_KEY_Alt_R:
167     case XKB_KEY_Super_L:
168     case XKB_KEY_Super_R:
169       goto done;
170 
171     case XKB_KEY_e:
172       if (hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
173         if (mode->completion != NULL) {
174           text = hikari_completion_cancel(mode->completion);
175           hikari_input_buffer_replace(input_buffer, text);
176           fini_completion();
177         }
178       } else {
179         put_char(input_buffer, keyboard, keycode);
180       }
181       break;
182 
183     case XKB_KEY_h:
184       fini_completion();
185       if (hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
186         hikari_input_buffer_remove_char(input_buffer);
187       } else {
188         put_char(input_buffer, keyboard, keycode);
189       }
190       break;
191 
192     case XKB_KEY_u:
193       fini_completion();
194       if (hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
195         hikari_input_buffer_clear(input_buffer);
196       } else {
197         put_char(input_buffer, keyboard, keycode);
198       }
199       break;
200 
201     case XKB_KEY_w:
202       fini_completion();
203       if (hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
204         hikari_input_buffer_remove_word(input_buffer);
205       } else {
206         put_char(input_buffer, keyboard, keycode);
207       }
208       break;
209 
210     case XKB_KEY_BackSpace:
211       fini_completion();
212       hikari_input_buffer_remove_char(input_buffer);
213       break;
214 
215     case XKB_KEY_Tab:
216       init_completion();
217       text = hikari_completion_next(mode->completion);
218       hikari_input_buffer_replace(input_buffer, text);
219       break;
220 
221     case XKB_KEY_ISO_Left_Tab:
222       init_completion();
223       text = hikari_completion_prev(mode->completion);
224       hikari_input_buffer_replace(input_buffer, text);
225       break;
226 
227     case XKB_KEY_c:
228     case XKB_KEY_d:
229       if (!hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
230         put_char(input_buffer, keyboard, keycode);
231         break;
232       }
233     case XKB_KEY_Escape:
234       hikari_server_enter_normal_mode(NULL);
235       goto done;
236 
237     case XKB_KEY_Return:
238       confirm_group_assign();
239       goto done;
240 
241     default:
242       put_char(input_buffer, keyboard, keycode);
243       break;
244   }
245 
246   update_state();
247 
248 done:
249   return;
250 }
251 
252 static void
key_handler(struct hikari_keyboard * keyboard,struct wlr_event_keyboard_key * event)253 key_handler(
254     struct hikari_keyboard *keyboard, struct wlr_event_keyboard_key *event)
255 {
256   if (event->state == WLR_KEY_PRESSED) {
257     uint32_t keycode = event->keycode + 8;
258     hikari_keyboard_for_keysym(keyboard, keycode, handle_keysym);
259   }
260 }
261 
262 static void
modifiers_handler(struct hikari_keyboard * keyboard)263 modifiers_handler(struct hikari_keyboard *keyboard)
264 {}
265 
266 static void
cancel(void)267 cancel(void)
268 {
269   struct hikari_workspace *workspace = hikari_server.workspace;
270   struct hikari_view *view = workspace->focus_view;
271   struct hikari_group_assign_mode *mode = get_mode();
272   struct hikari_indicator *indicator = &hikari_server.indicator;
273 
274   hikari_indicator_set_color_group(
275       indicator, hikari_configuration->indicator_selected);
276 
277   if (view != NULL) {
278     struct hikari_output *output = view->output;
279     struct hikari_indicator *indicator = &hikari_server.indicator;
280 
281     hikari_indicator_damage(indicator, view);
282 
283     hikari_indicator_update_group(indicator, output, view->group->name);
284 
285     hikari_view_damage_border(view);
286   }
287 
288   if (mode->group != NULL) {
289     hikari_group_damage(mode->group);
290     mode->group = NULL;
291   }
292 
293   hikari_input_buffer_clear(&mode->input_buffer);
294   fini_completion();
295 }
296 
297 static void
button_handler(struct hikari_cursor * cursor,struct wlr_event_pointer_button * event)298 button_handler(
299     struct hikari_cursor *cursor, struct wlr_event_pointer_button *event)
300 {}
301 
302 static void
cursor_move(uint32_t time_msec)303 cursor_move(uint32_t time_msec)
304 {}
305 
306 void
hikari_group_assign_mode_init(struct hikari_group_assign_mode * group_assign_mode)307 hikari_group_assign_mode_init(
308     struct hikari_group_assign_mode *group_assign_mode)
309 {
310   group_assign_mode->mode.key_handler = key_handler;
311   group_assign_mode->mode.button_handler = button_handler;
312   group_assign_mode->mode.modifiers_handler = modifiers_handler;
313   group_assign_mode->mode.render = hikari_renderer_group_assign_mode;
314   group_assign_mode->mode.cancel = cancel;
315   group_assign_mode->mode.cursor_move = cursor_move;
316   group_assign_mode->group = NULL;
317   group_assign_mode->completion = NULL;
318 }
319 
320 void
hikari_group_assign_mode_enter(struct hikari_view * view)321 hikari_group_assign_mode_enter(struct hikari_view *view)
322 {
323   struct hikari_group_assign_mode *mode = &hikari_server.group_assign_mode;
324 
325   struct hikari_output *output = hikari_server.workspace->output;
326   struct hikari_indicator *indicator = &hikari_server.indicator;
327   struct wlr_box *geometry = hikari_view_border_geometry(view);
328 
329   mode->group = view->group;
330   hikari_server.mode = (struct hikari_mode *)mode;
331 
332   hikari_input_buffer_replace(&mode->input_buffer, view->group->name);
333 
334   hikari_indicator_set_color_group(
335       indicator, hikari_configuration->indicator_insert);
336 
337   hikari_indicator_update_group(indicator, output, view->group->name);
338   hikari_indicator_damage_group(indicator, output, geometry);
339 }
340