GCC Code Coverage Report


Directory: ./
File: src/blocks.c
Date: 2024-08-06 23:19:24
Exec Total Coverage
Lines: 180 267 67.4%
Functions: 16 19 84.2%
Branches: 49 120 40.8%

Line Branch Exec Source
1 // SPDX-License-Identifier: GPL-3.0-or-later
2 // Copyright (C) 2020 Omar Castro
3
4 #define G_LOG_DOMAIN "BlocksMode"
5
6
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <signal.h>
10 #include <fcntl.h>
11
12 #include <rofi/mode.h>
13 #include <rofi/helper.h>
14 #include <rofi/mode-private.h>
15 #include <rofi/rofi-icon-fetcher.h>
16
17 #include <glib-object.h>
18 #include <json-glib/json-glib.h>
19
20 #include <stdint.h>
21
22 #include "string_utils.h"
23 #include "page_data.h"
24 #include "blocks_mode_data.h"
25
26 #ifdef __GNUC__
27 # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
28 #else
29 # define UNUSED(x) UNUSED_ ## x
30 #endif
31
32 typedef struct RofiViewState RofiViewState;
33 void rofi_view_switch_mode ( RofiViewState *state, Mode *mode );
34 RofiViewState * rofi_view_get_active ( void );
35 extern void rofi_view_set_overlay(RofiViewState * state, const char *text);
36 extern void rofi_view_reload ( void );
37 const char * rofi_view_get_user_input ( const RofiViewState *state );
38 unsigned int rofi_view_get_selected_line ( const RofiViewState *state );
39 void rofi_view_set_selected_line ( const RofiViewState *state, unsigned int selected_line );
40 unsigned int rofi_view_get_next_position ( const RofiViewState *state );
41 void rofi_view_handle_text ( RofiViewState *state, char *text );
42 void rofi_view_clear_input ( RofiViewState *state );
43 G_MODULE_EXPORT Mode mode;
44
45
46 const gchar* CmdArg__BLOCKS_WRAP = "-blocks-wrap";
47 const gchar* CmdArg__BLOCKS_PROMPT = "-blocks-prompt";
48 const gchar* CmdArg__MARKUP_ROWS = "-markup-rows";
49
50 typedef enum {
51 Event__INPUT_CHANGE,
52 Event__CUSTOM_KEY,
53 Event__ACTIVE_ENTRY,
54 Event__SELECT_ENTRY,
55 Event__DELETE_ENTRY,
56 Event__EXEC_CUSTOM_INPUT
57 } Event;
58
59 static const char *event_enum_labels[] = {
60 "INPUT_CHANGE",
61 "CUSTOM_KEY",
62 "ACTIVE_ENTRY",
63 "SELECT_ENTRY",
64 "DELETE_ENTRY",
65 "EXEC_CUSTOM_INPUT"
66 };
67
68 static const char *event_labels[] = {
69 "input change",
70 "custom key",
71 "active entry",
72 "select entry",
73 "delete entry",
74 "execute custom input"
75 };
76
77 /**************
78 rofi extension
79 ****************/
80
81 9 unsigned int blocks_mode_rofi_view_get_current_position(RofiViewState * rofiViewState, PageData * pageData){
82 9 unsigned int next_position = rofi_view_get_next_position(rofiViewState);
83 9 unsigned int length = page_data_get_number_of_lines(pageData);
84
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if(next_position <= 0 || next_position >= UINT32_MAX - 10) {
85 return length - 1;
86 } else {
87 9 return next_position - 1;
88 }
89 }
90
91
92 /**************************************
93 extended mode pirvate data methods
94 **************************************/
95
96
97
98 3 void blocks_mode_private_data_write_to_channel ( BlocksModePrivateData * data, Event event, const char * action_value, const char * action_data){
99 3 GIOChannel * write_channel = data->write_channel;
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(data->write_channel == NULL){
101 //gets here when the script exits or there was an error loading it
102 return;
103 }
104 3 const gchar * format = data->input_format->str;
105 3 gchar * format_result = str_replace(format, "{{name}}", event_labels[event]);
106 3 format_result = str_replace_in(&format_result, "{{name_enum}}", event_enum_labels[event]);
107 3 format_result = str_replace_in(&format_result, "{{value}}", action_value);
108 3 format_result = str_replace_in(&format_result, "{{data}}", action_data);
109 3 format_result = str_replace_in_escaped(&format_result, "{{name_escaped}}", event_labels[event]);
110 3 format_result = str_replace_in_escaped(&format_result, "{{value_escaped}}", action_value);
111 3 format_result = str_replace_in_escaped(&format_result, "{{data_escaped}}", action_data);
112 3 g_debug("sending event: %s", format_result);
113 gsize bytes_witten;
114 3 g_io_channel_write_chars(write_channel, format_result, -1, &bytes_witten, &data->error);
115 3 g_io_channel_write_unichar(write_channel, '\n', &data->error);
116 3 g_io_channel_flush(write_channel, &data->error);
117 3 g_free(format_result);
118 }
119
120 12 void blocks_mode_verify_input_change ( BlocksModePrivateData * data, const char * new_input_value){
121 12 PageData * pageData = data->currentPageData;
122 12 GString * inputStr = pageData->input;
123 12 bool inputChanged = g_strcmp0(inputStr->str, new_input_value) != 0;
124
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 if(inputChanged){
125 3 g_string_assign(inputStr, new_input_value);
126
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(data->input_action == InputAction__SEND_ACTION ){
127 3 blocks_mode_private_data_write_to_channel(data, Event__INPUT_CHANGE, new_input_value, "");
128 }
129 }
130 12 }
131
132 /**************************
133 mode extension methods
134 **************************/
135
136 136 static BlocksModePrivateData * mode_get_private_data_extended_mode(const Mode *sw){
137 136 return (BlocksModePrivateData *) mode_get_private_data( sw );
138 }
139
140 55 static PageData * mode_get_private_data_current_page(const Mode *sw){
141 55 return mode_get_private_data_extended_mode( sw )->currentPageData;
142 }
143
144 1 static void set_active_entry(gpointer context){
145 1 BlocksModePrivateData *data = (BlocksModePrivateData *) context;
146 // we also check for entry_to_focus just in case
147 // the state is updated to render another page
148 1 gint64 entry_to_focus = data->entry_to_focus;
149 1 bool willFocusToEntry = entry_to_focus >= 0;
150
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(willFocusToEntry){
151 1 RofiViewState * rofiViewState = rofi_view_get_active();
152 1 rofi_view_set_selected_line(rofiViewState, (unsigned int) entry_to_focus);
153 }
154 1 }
155
156 /*******************
157 main loop sources
158 ********************/
159
160 // GIOChannel watch, called when there is output to read from child proccess
161 3 static gboolean on_new_input ( GIOChannel *source, GIOCondition UNUSED(condition), gpointer context )
162 {
163 3 Mode *sw = (Mode *) context;
164 3 RofiViewState * state = rofi_view_get_active();
165
166 3 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
167
168 3 GString * buffer = data->buffer;
169 3 GString * active_line = data->active_line;
170
171 3 gboolean newline = FALSE;
172
173 3 GError * error = NULL;
174 gunichar unichar;
175 GIOStatus status;
176
177 3 status = g_io_channel_read_unichar(source, &unichar, &error);
178
179 //when there is nothing to read, status is G_IO_STATUS_AGAIN
180
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 3 times.
303 while(status == G_IO_STATUS_NORMAL) {
181 300 g_string_append_unichar(buffer, unichar);
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 297 times.
300 if( unichar == '\n' ){
183
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(buffer->len > 1){ //input is not an empty line
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(newline){
185 g_debug("previous line ignored since a new line is received");
186 }
187 3 g_debug("received new line: %s", buffer->str);
188 3 g_string_assign(active_line, buffer->str);
189 3 newline=TRUE;
190 }
191 3 g_string_set_size(buffer, 0);
192 }
193 300 status = g_io_channel_read_unichar(source, &unichar, &error);
194 }
195
196
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(newline){
197 3 g_debug("handling received line");
198
199 3 GString * oldOverlay = g_string_new(page_data_get_overlay_or_empty_string(data->currentPageData));
200 3 GString * prompt = data->currentPageData->prompt;
201 3 GString * input = data->currentPageData->input;
202
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GString * oldPrompt = prompt == NULL ? NULL : g_string_new(prompt->str);
204
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 GString * oldInput = input == NULL ? NULL : g_string_new(input->str);
205
206 3 blocks_mode_private_data_update_page(data);
207
208 3 GString * newOverlay = g_string_new(page_data_get_overlay_or_empty_string(data->currentPageData));
209 3 GString * newPrompt = data->currentPageData->prompt;
210 3 GString * newInput = data->currentPageData->input;
211 3 gint64 entry_to_focus = data->entry_to_focus;
212
213 3 bool overlayChanged = !g_string_equal(oldOverlay, newOverlay);
214
3/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
3 bool promptChanged = newPrompt != NULL && (oldPrompt == NULL || !g_string_equal(oldPrompt, newPrompt));
215
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
3 bool inputChanged = newInput != NULL && (oldInput == NULL || !g_string_equal(oldInput, newInput));
216 3 bool willFocusToEntry = entry_to_focus >= 0;
217 3 bool isFirstPaint = data->paintNumber == 0;
218
219
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(overlayChanged){
221 RofiViewState * state = rofi_view_get_active();
222 rofi_view_set_overlay(state, (newOverlay->len > 0) ? newOverlay->str : NULL);
223 }
224
225
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if(promptChanged){
226 2 g_free ( sw->display_name );
227 2 sw->display_name = g_strdup ( newPrompt->str );
228 // rofi_view_reload does not update prompt, that is why this is needed
229 2 rofi_view_switch_mode ( state, sw );
230 }
231
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(inputChanged){
233 RofiViewState * rofiViewState = rofi_view_get_active();
234 rofi_view_clear_input(rofiViewState);
235 rofi_view_handle_text(rofiViewState, newInput->str);
236 }
237
238
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(willFocusToEntry){
239 1 RofiViewState * rofiViewState = rofi_view_get_active();
240 1 g_debug("entry_to_focus %li", entry_to_focus);
241
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(isFirstPaint){
242 // on first paint rofi_view_set_selected_line does not work correctly,
243 // so we wait for a frame to fix it, we are going to wait a frame
244 // of a 30fps monitor, as it supports current and old monitors
245 1 unsigned int delay = 1000/30;
246 1 g_timeout_add_once (delay, set_active_entry, data);
247 }
248 1 rofi_view_set_selected_line(rofiViewState, (unsigned int) entry_to_focus);
249 }
250
251 3 g_string_free(oldOverlay, TRUE);
252 3 g_string_free(newOverlay, TRUE);
253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(oldPrompt != NULL){ g_string_free(oldPrompt, TRUE); }
254
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(oldInput != NULL){ g_string_free(oldInput, TRUE); }
255
256 3 g_debug("reloading rofi view");
257
258 3 rofi_view_reload();
259 }
260
261 3 return G_SOURCE_CONTINUE;
262 }
263
264 // spawn watch, called when child exited
265 3 static void on_child_status (GPid pid, gint status, gpointer context)
266 {
267
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 g_message ("Child %" G_PID_FORMAT " exited %s", pid,
268 g_spawn_check_wait_status (status, NULL) ? "normally" : "abnormally");
269 3 Mode *sw = (Mode *) context;
270 3 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
271 3 g_spawn_close_pid (pid);
272 3 data->write_channel = NULL;
273
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if(data->close_on_child_exit){
274 3 exit(0);
275 }
276 }
277
278 // idle, called after rendering
279 9 static void on_render(gpointer context){
280 9 g_debug("%s", "calling on_render");
281
282 9 Mode *sw = (Mode *) context;
283 9 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
284 9 RofiViewState * rofiViewState = rofi_view_get_active();
285
286 /**
287 * Mode._preprocess_input is not called when input is empty,
288 * the only method called when the input changes to empty is blocks_mode_get_display_value
289 * which later this method is called, that is reason the following 3 lines are added.
290 */
291
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if(rofiViewState != NULL){
292 9 blocks_mode_verify_input_change(data, rofi_view_get_user_input(rofiViewState));
293 9 g_debug("%s %i", "on_render.selected line", rofi_view_get_selected_line(rofiViewState));
294 9 g_debug("%s %i", "on_render.next pos", rofi_view_get_next_position(rofiViewState));
295 9 g_debug("%s %i", "on_render.active line", blocks_mode_rofi_view_get_current_position(rofiViewState, data->currentPageData));
296 }
297
298 9 }
299
300 // function used on g_idle_add, it is here to guarantee that this is called once
301 // each time the mode content is rendered
302 9 static gboolean on_render_callback(gpointer context){
303 9 on_render(context);
304 9 Mode *sw = (Mode *) context;
305 9 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
306 9 data->waiting_for_idle = FALSE;
307 9 return FALSE;
308 }
309
310
311
312 /************************
313 extended mode methods
314 ***********************/
315
316
317 3 static int blocks_mode_init ( Mode *sw )
318 {
319
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if ( mode_get_private_data ( sw ) == NULL ) {
320 3 BlocksModePrivateData *pd = blocks_mode_private_data_new();
321 3 mode_set_private_data ( sw, (void *) pd );
322 3 char *cmd = NULL;
323
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (find_arg_str(CmdArg__MARKUP_ROWS, &cmd)) {
324 pd->currentPageData->markup_default = MarkupStatus_ENABLED;
325 }
326
327 3 char *prompt = NULL;
328
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (find_arg_str(CmdArg__BLOCKS_PROMPT, &prompt)) {
329 sw->display_name = g_strdup ( prompt );
330 }
331
332
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (find_arg_str(CmdArg__BLOCKS_WRAP, &cmd)) {
333 3 GError *error = NULL;
334 int cmd_input_fd;
335 int cmd_output_fd;
336 3 char **argv = NULL;
337
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ( !g_shell_parse_argv ( cmd, NULL, &argv, &error ) ){
338 fprintf(stderr, "Unable to parse cmdline options: %s\n", error->message);
339 g_error_free ( error );
340 return 0;
341 }
342
343
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ( ! g_spawn_async_with_pipes ( NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &(pd->cmd_pid), &(cmd_input_fd), &(cmd_output_fd), NULL, &error)) {
344 fprintf(stderr, "Unable to exec %s\n", error->message);
345 char buffer[1024];
346 char * cmd_escaped = str_new_escaped_for_json_string(cmd);
347 char * error_message_escaped = str_new_escaped_for_json_string(error->message);
348 snprintf(buffer, sizeof(buffer),
349 "{\"close on exit\": false, \"message\":\"Error loading %s:%s\"}\n",
350 cmd_escaped,
351 error_message_escaped
352 );
353 fprintf(stderr, "message: %s\n", buffer);
354
355 g_string_assign(pd->active_line, buffer);
356 blocks_mode_private_data_update_page(pd);
357 g_error_free ( error );
358 g_free(cmd_escaped);
359 g_free(error_message_escaped);
360 return TRUE;
361 }
362
363 3 g_strfreev(argv);
364
365 3 pd->read_channel_fd = cmd_output_fd;
366 3 pd->write_channel_fd = cmd_input_fd;
367
368 3 int retval = fcntl( pd->read_channel_fd, F_SETFL, fcntl(pd->read_channel_fd, F_GETFL) | O_NONBLOCK);
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (retval != 0){
370
371 fprintf(stderr,"Error setting non block on output pipe\n");
372 kill(pd->cmd_pid, SIGTERM);
373 exit(1);
374 }
375 3 pd->read_channel = g_io_channel_unix_new(pd->read_channel_fd);
376 3 pd->write_channel = g_io_channel_unix_new(pd->write_channel_fd);
377 3 g_child_watch_add (pd->cmd_pid, on_child_status, sw);
378
379 } else {
380 int retval = fcntl( STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
381 if (retval != 0){
382 fprintf(stderr,"Error setting non block on output pipe\n");
383 exit(1);
384 }
385 pd->read_channel = g_io_channel_unix_new(STDIN_FILENO);
386 pd->write_channel = g_io_channel_unix_new(STDOUT_FILENO);
387 }
388
389 3 pd->read_channel_watcher = g_io_add_watch(pd->read_channel, G_IO_IN, on_new_input, sw);
390 }
391 3 return TRUE;
392 }
393 8 static unsigned int blocks_mode_get_num_entries ( const Mode *sw )
394 {
395 8 g_debug("%s", "blocks_mode_get_num_entries");
396 8 PageData * pageData = mode_get_private_data_current_page( sw );
397 8 return page_data_get_number_of_lines(pageData);
398 }
399
400 static ModeMode blocks_mode_result ( Mode *sw, int mretv, char **input, unsigned int selected_line )
401 {
402 ModeMode retv = MODE_EXIT;
403 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
404 PageData * pageData = data->currentPageData;
405 if ( mretv & MENU_NEXT ) {
406 retv = NEXT_DIALOG;
407 } else if ( mretv & MENU_PREVIOUS ) {
408 retv = PREVIOUS_DIALOG;
409 } else if ( mretv & MENU_CUSTOM_COMMAND ) {
410 if(selected_line >= pageData->lines->len){ return RELOAD_DIALOG; }
411
412 retv = ( mretv & MENU_LOWER_MASK );
413 int custom_key = retv%20 + 1;
414 char str[8];
415 snprintf(str, 8, "%d", custom_key);
416
417 LineData * lineData = &g_array_index (pageData->lines, LineData, selected_line);
418 blocks_mode_private_data_write_to_channel(data, Event__ACTIVE_ENTRY, lineData->text, lineData->data);
419 blocks_mode_private_data_write_to_channel(data, Event__CUSTOM_KEY, str, "");
420
421 retv = RELOAD_DIALOG;
422 } else if ( ( mretv & MENU_OK ) ) {
423 if(selected_line >= pageData->lines->len){ return RELOAD_DIALOG; }
424 LineData * lineData = &g_array_index (pageData->lines, LineData, selected_line);
425 if (lineData->nonselectable) { return RELOAD_DIALOG; }
426 blocks_mode_private_data_write_to_channel(data, Event__SELECT_ENTRY, lineData->text, lineData->data);
427 retv = RELOAD_DIALOG;
428 } else if ( ( mretv & MENU_ENTRY_DELETE ) == MENU_ENTRY_DELETE ) {
429 if(selected_line >= pageData->lines->len){ return RELOAD_DIALOG; }
430 LineData * lineData = &g_array_index (pageData->lines, LineData, selected_line);
431 blocks_mode_private_data_write_to_channel(data, Event__DELETE_ENTRY, lineData->text, lineData->data);
432 retv = RELOAD_DIALOG;
433 } else if ( ( mretv & MENU_CUSTOM_INPUT ) ) {
434 blocks_mode_private_data_write_to_channel(data, Event__EXEC_CUSTOM_INPUT, *input, "");
435 retv = RELOAD_DIALOG;
436 }
437 return retv;
438 }
439
440 static void blocks_mode_destroy ( Mode *sw )
441 {
442 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
443 if ( data != NULL ) {
444 blocks_mode_private_data_update_destroy(data);
445 mode_set_private_data ( sw, NULL );
446 }
447 }
448
449 static cairo_surface_t * blocks_mode_get_icon ( const Mode *sw, unsigned int selected_line, unsigned int height ){
450 PageData * pageData = mode_get_private_data_current_page( sw );
451 LineData * lineData = page_data_get_line_by_index_or_else(pageData, selected_line, NULL);
452 if(lineData == NULL){
453 return NULL;
454 }
455
456 const gchar * icon = lineData->icon;
457 if(icon == NULL || icon[0] == '\0'){
458 return NULL;
459 }
460
461 if(lineData->icon_fetch_uid <= 0){
462 lineData->icon_fetch_uid = rofi_icon_fetcher_query ( icon, height );
463 }
464 return rofi_icon_fetcher_get ( lineData->icon_fetch_uid );
465 }
466
467
468
469 39 static char * blocks_mode_get_display_value ( const Mode *sw, unsigned int selected_line, int *state, G_GNUC_UNUSED GList **attr_list, int get_entry )
470 {
471 39 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
472
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 30 times.
39 if(!data->waiting_for_idle){
473 9 data->waiting_for_idle = TRUE;
474 9 g_idle_add (on_render_callback, (void *) sw);
475 }
476
477 39 PageData * pageData = mode_get_private_data_current_page( sw );
478 39 LineData * lineData = page_data_get_line_by_index_or_else(pageData, selected_line, NULL);
479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if(lineData == NULL){
480 *state |= 16;
481 return get_entry ? g_strdup("") : NULL;
482 }
483
484 39 *state |=
485 39 1 * lineData->urgent +
486 39 2 * lineData->highlight +
487 39 8 * lineData->markup;
488
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
78 return get_entry ? g_strdup(lineData->text) : NULL;
489 }
490
491 15 static int blocks_mode_token_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned int selected_line )
492 {
493 15 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
494 15 PageData * pageData = data->currentPageData;
495 15 LineData * lineData = page_data_get_line_by_index_or_else(pageData, selected_line, NULL);
496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(lineData == NULL){
497 return FALSE;
498 }
499
500
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if(data->input_action == InputAction__SEND_ACTION){
501 15 return TRUE;
502 }
503 return helper_token_match ( tokens, lineData->text);
504 }
505
506 8 static char * blocks_mode_get_message ( const Mode *sw )
507 {
508 8 g_debug("%s", "blocks_mode_get_message");
509 8 PageData * pageData = mode_get_private_data_current_page( sw );
510
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
12 gchar* result = page_data_is_message_empty(pageData) ? NULL : g_strdup(page_data_get_message_or_empty_string(pageData));
511 8 return result;
512 }
513
514 3 static char * blocks_mode_preprocess_input ( Mode *sw, const char *input )
515 {
516 3 g_debug("%s", "blocks_mode_preprocess_input");
517 3 BlocksModePrivateData *data = mode_get_private_data_extended_mode( sw );
518 3 blocks_mode_verify_input_change(data, input);
519 3 return g_strdup(input);
520 }
521
522 Mode mode =
523 {
524 .abi_version = ABI_VERSION,
525 .name = "blocks",
526 .cfg_name_key = "display-blocks",
527 ._init = blocks_mode_init,
528 ._get_num_entries = blocks_mode_get_num_entries,
529 ._result = blocks_mode_result,
530 ._destroy = blocks_mode_destroy,
531 ._token_match = blocks_mode_token_match,
532 ._get_icon = blocks_mode_get_icon,
533 ._get_display_value = blocks_mode_get_display_value,
534 ._get_message = blocks_mode_get_message,
535 ._get_completion = NULL,
536 ._preprocess_input = blocks_mode_preprocess_input,
537 .private_data = NULL,
538 .free = NULL,
539 };
540