1 #include <hikari/mark_assign_mode.h>
2 
3 #include <wlr/types/wlr_seat.h>
4 
5 #include <hikari/configuration.h>
6 #include <hikari/indicator.h>
7 #include <hikari/indicator_frame.h>
8 #include <hikari/keyboard.h>
9 #include <hikari/mark.h>
10 #include <hikari/normal_mode.h>
11 #include <hikari/renderer.h>
12 #include <hikari/view.h>
13 
14 static struct hikari_mark_assign_mode *
get_mode(void)15 get_mode(void)
16 {
17   struct hikari_mark_assign_mode *mode = &hikari_server.mark_assign_mode;
18 
19   assert(mode == (struct hikari_mark_assign_mode *)hikari_server.mode);
20 
21   return mode;
22 }
23 
24 static void
clear_conflict(struct hikari_mark_assign_mode * mode,struct hikari_mark * mark)25 clear_conflict(struct hikari_mark_assign_mode *mode, struct hikari_mark *mark)
26 {
27   if (mark != NULL && mark->view != NULL) {
28     struct hikari_view *view = mark->view;
29 
30     hikari_view_damage_border(view);
31     hikari_indicator_damage(&mode->indicator, view);
32   }
33 }
34 
35 static void
update_state(struct hikari_mark * mark)36 update_state(struct hikari_mark *mark)
37 {
38   struct hikari_mark_assign_mode *mode = get_mode();
39   struct hikari_workspace *workspace = hikari_server.workspace;
40   struct hikari_view *view = workspace->focus_view;
41   struct hikari_output *output = workspace->output;
42   struct wlr_box *geometry = hikari_view_border_geometry(view);
43   struct hikari_indicator *indicator = &hikari_server.indicator;
44   struct hikari_mark *pending_mark = mode->pending_mark;
45 
46   if (pending_mark != mark) {
47     clear_conflict(mode, pending_mark);
48   }
49 
50   if (mark == NULL) {
51     hikari_indicator_set_color_mark(
52         indicator, hikari_configuration->indicator_insert);
53     hikari_indicator_update_mark(indicator, output, " ");
54   } else {
55     float *indicator_color;
56     struct hikari_view *mark_view = mark->view;
57 
58     if (mark_view != NULL) {
59       hikari_indicator_update(&mode->indicator, mark_view);
60 
61       hikari_view_damage_border(mark_view);
62       hikari_indicator_damage(&mode->indicator, mark_view);
63 
64       indicator_color = hikari_configuration->indicator_conflict;
65     } else {
66       indicator_color = hikari_configuration->indicator_insert;
67     }
68 
69     hikari_indicator_set_color_mark(indicator, indicator_color);
70     hikari_indicator_update_mark(indicator, output, mark->name);
71   }
72 
73   hikari_indicator_damage_mark(indicator, output, geometry);
74 
75   mode->pending_mark = mark;
76 }
77 
78 static void
confirm_mark_assign(void)79 confirm_mark_assign(void)
80 {
81   struct hikari_mark_assign_mode *mode = get_mode();
82   struct hikari_workspace *workspace = hikari_server.workspace;
83   struct hikari_view *view = workspace->focus_view;
84   struct hikari_output *output = workspace->output;
85   struct hikari_mark *pending_mark = mode->pending_mark;
86   struct hikari_indicator *indicator = &hikari_server.indicator;
87 
88   hikari_indicator_set_color_mark(
89       indicator, hikari_configuration->indicator_selected);
90 
91   if (pending_mark != NULL) {
92     clear_conflict(mode, pending_mark);
93 
94     hikari_mark_set(pending_mark, view);
95     hikari_indicator_update_mark(indicator, output, mode->pending_mark->name);
96 
97     mode->pending_mark = NULL;
98   } else {
99     if (view->mark != NULL) {
100       hikari_mark_clear(view->mark);
101     }
102 
103     hikari_indicator_update_mark(indicator, output, "");
104   }
105 
106   hikari_server_enter_normal_mode(NULL);
107 }
108 
109 static void
select_mark(struct hikari_keyboard * keyboard,uint32_t keycode)110 select_mark(struct hikari_keyboard *keyboard, uint32_t keycode)
111 {
112   uint32_t codepoint = hikari_keyboard_get_codepoint(keyboard, keycode);
113 
114   struct hikari_mark *mark;
115   if (hikari_mark_get(codepoint, &mark)) {
116     update_state(mark);
117   }
118 }
119 
120 static void
handle_keysym(struct hikari_keyboard * keyboard,uint32_t keycode,xkb_keysym_t sym)121 handle_keysym(
122     struct hikari_keyboard *keyboard, uint32_t keycode, xkb_keysym_t sym)
123 {
124   switch (sym) {
125     case XKB_KEY_c:
126     case XKB_KEY_d:
127       if (!hikari_keyboard_check_modifier(keyboard, WLR_MODIFIER_CTRL)) {
128         select_mark(keyboard, keycode);
129         break;
130       }
131     case XKB_KEY_Escape:
132       hikari_server_enter_normal_mode(NULL);
133       break;
134 
135     case XKB_KEY_Return:
136       confirm_mark_assign();
137       break;
138 
139     case XKB_KEY_BackSpace:
140       update_state(NULL);
141       break;
142 
143     default:
144       select_mark(keyboard, keycode);
145       break;
146   }
147 }
148 
149 static void
assign_mark(struct wlr_event_keyboard_key * event,struct hikari_keyboard * keyboard)150 assign_mark(
151     struct wlr_event_keyboard_key *event, struct hikari_keyboard *keyboard)
152 {
153   assert(hikari_server.workspace->focus_view != NULL);
154 
155   uint32_t keycode = event->keycode + 8;
156 
157   hikari_keyboard_for_keysym(keyboard, keycode, handle_keysym);
158 }
159 
160 static void
key_handler(struct hikari_keyboard * keyboard,struct wlr_event_keyboard_key * event)161 key_handler(
162     struct hikari_keyboard *keyboard, struct wlr_event_keyboard_key *event)
163 {
164   if (event->state == WLR_KEY_PRESSED) {
165     assign_mark(event, keyboard);
166   }
167 }
168 
169 static void
modifiers_handler(struct hikari_keyboard * keyboard)170 modifiers_handler(struct hikari_keyboard *keyboard)
171 {}
172 
173 static void
cancel(void)174 cancel(void)
175 {
176   struct hikari_workspace *workspace = hikari_server.workspace;
177   struct hikari_view *view = workspace->focus_view;
178   struct hikari_mark_assign_mode *mode = get_mode();
179   struct hikari_indicator *indicator = &hikari_server.indicator;
180 
181   clear_conflict(mode, mode->pending_mark);
182 
183   hikari_indicator_set_color_mark(
184       indicator, hikari_configuration->indicator_selected);
185 
186   if (view != NULL) {
187     struct hikari_output *output = view->output;
188 
189     if (view->mark != NULL) {
190       hikari_indicator_update_mark(indicator, output, view->mark->name);
191     } else {
192       hikari_indicator_update_mark(indicator, output, "");
193     }
194 
195     hikari_indicator_damage(indicator, view);
196     hikari_view_damage_border(view);
197   }
198 
199   hikari_server.mark_assign_mode.pending_mark = NULL;
200 }
201 
202 static void
button_handler(struct hikari_cursor * cursor,struct wlr_event_pointer_button * event)203 button_handler(
204     struct hikari_cursor *cursor, struct wlr_event_pointer_button *event)
205 {}
206 
207 static void
cursor_move(uint32_t time_msec)208 cursor_move(uint32_t time_msec)
209 {}
210 
211 void
hikari_mark_assign_mode_init(struct hikari_mark_assign_mode * mark_assign_mode)212 hikari_mark_assign_mode_init(struct hikari_mark_assign_mode *mark_assign_mode)
213 {
214   mark_assign_mode->mode.key_handler = key_handler;
215   mark_assign_mode->mode.button_handler = button_handler;
216   mark_assign_mode->mode.modifiers_handler = modifiers_handler;
217   mark_assign_mode->mode.render = hikari_renderer_mark_assign_mode;
218   mark_assign_mode->mode.cancel = cancel;
219   mark_assign_mode->mode.cursor_move = cursor_move;
220 
221   hikari_indicator_init(
222       &mark_assign_mode->indicator, hikari_configuration->indicator_conflict);
223 }
224 
225 void
hikari_mark_assign_mode_fini(struct hikari_mark_assign_mode * mark_assign_mode)226 hikari_mark_assign_mode_fini(struct hikari_mark_assign_mode *mark_assign_mode)
227 {
228   hikari_indicator_fini(&mark_assign_mode->indicator);
229 }
230 
231 void
hikari_mark_assign_mode_enter(struct hikari_view * view)232 hikari_mark_assign_mode_enter(struct hikari_view *view)
233 {
234   assert(view == hikari_server.workspace->focus_view);
235 
236   struct wlr_box *geometry = hikari_view_border_geometry(view);
237   struct hikari_output *output = view->output;
238   struct hikari_mark *mark = view->mark;
239   struct hikari_indicator *indicator = &hikari_server.indicator;
240 
241   hikari_server.mark_assign_mode.pending_mark = NULL;
242   hikari_server.mode = (struct hikari_mode *)&hikari_server.mark_assign_mode;
243 
244   hikari_indicator_set_color_mark(
245       indicator, hikari_configuration->indicator_insert);
246 
247   if (mark == NULL) {
248     hikari_indicator_update_mark(indicator, output, " ");
249   } else {
250     hikari_indicator_update_mark(indicator, output, mark->name);
251   }
252 
253   hikari_indicator_damage_mark(indicator, output, geometry);
254 }
255