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