rofi 2.0.0
view.c
Go to the documentation of this file.
1/*
2 * rofi
3 *
4 * MIT/X11 License
5 * Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
29#define G_LOG_DOMAIN "View"
30
31#include <config.h>
32#include <locale.h>
33#include <signal.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <time.h>
39#include <unistd.h>
40
41#include <glib.h>
42
43#include "rofi.h"
44
45#include "settings.h"
46#include "timings.h"
47
48#include "display.h"
49#include "helper-theme.h"
50#include "helper.h"
51#include "mode.h"
52
53#include "view-internal.h"
54#include "view.h"
55
56#include "theme.h"
57
58#ifdef ENABLE_XCB
59#include "xcb-internal.h"
60#include "xcb.h"
61#else
62#include "xcb-dummy.h"
63#endif
64
65static const view_proxy *proxy;
66
67void view_init(const view_proxy *view_in) { proxy = view_in; }
68
70GThreadPool *tpool = NULL;
71
74
76 .main_window = XCB_WINDOW_NONE,
77 .flags = MENU_NORMAL,
78 .views = G_QUEUE_INIT,
79 .refilter_timeout = 0,
80 .refilter_timeout_count = 0,
81 .max_refilter_time = 0.0,
82 .delayed_mode = FALSE,
83 .user_timeout = 0,
84 .overlay_timeout = 0,
85 .entry_history_enable = TRUE,
86 .entry_history = NULL,
87 .entry_history_length = 0,
88 .entry_history_index = 0,
89};
90
91static char *get_matching_state(RofiViewState* state) {
92 if (state->case_sensitive) {
93 if (config.sort) {
94 return "±";
95 } else {
96 return "-";
97 }
98 } else {
99 if (config.sort) {
100 return "+";
101 }
102 }
103 return " ";
104}
105
109static int lev_sort(const void *p1, const void *p2, void *arg) {
110 const int *a = p1;
111 const int *b = p2;
112 int *distances = arg;
113
114 return distances[*a] - distances[*b];
115}
116
117static void screenshot_taken_user_callback(const char *path) {
118 if (config.on_screenshot_taken == NULL)
119 return;
120
121 char **args = NULL;
122 int argv = 0;
123 helper_parse_setup(config.on_screenshot_taken, &args, &argv, "{path}", path,
124 (char *)0);
125 if (args != NULL)
126 helper_execute(NULL, args, "", config.on_screenshot_taken, NULL);
127}
128
134 if (state == NULL || state->main_window == NULL) {
135 g_warning("Nothing to screenshot.");
136 return;
137 }
138 const char *outp = g_getenv("ROFI_PNG_OUTPUT");
139 const char *xdg_pict_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
140 if (outp == NULL && xdg_pict_dir == NULL) {
141 g_warning("XDG user picture directory or ROFI_PNG_OUTPUT is not set. "
142 "Cannot store screenshot.");
143 return;
144 }
145 // Get current time.
146 GDateTime *now = g_date_time_new_now_local();
147 // Format filename.
148 char *timestmp = g_date_time_format(now, "rofi-%Y-%m-%d-%H%M");
149 char *filename = g_strdup_printf("%s-%05d.png", timestmp, 0);
150 // Build full path
151 char *fpath = NULL;
152 if (outp == NULL) {
153 int index = 0;
154 fpath = g_build_filename(xdg_pict_dir, filename, NULL);
155 while (g_file_test(fpath, G_FILE_TEST_EXISTS) && index < 99999) {
156 g_free(fpath);
157 g_free(filename);
158 // Try the next index.
159 index++;
160 // Format filename.
161 filename = g_strdup_printf("%s-%05d.png", timestmp, index);
162 // Build full path
163 fpath = g_build_filename(xdg_pict_dir, filename, NULL);
164 }
165 } else {
166 fpath = g_strdup(outp);
167 }
168 fprintf(stderr, color_green "Storing screenshot %s\n" color_reset, fpath);
169 cairo_surface_t *surf = cairo_image_surface_create(
170 CAIRO_FORMAT_ARGB32, state->width, state->height);
171 cairo_status_t status = cairo_surface_status(surf);
172 if (status != CAIRO_STATUS_SUCCESS) {
173 g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
174 cairo_status_to_string(status));
175 } else {
176 cairo_t *draw = cairo_create(surf);
177 status = cairo_status(draw);
178 if (status != CAIRO_STATUS_SUCCESS) {
179 g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
180 cairo_status_to_string(status));
181 } else {
182 widget_draw(WIDGET(state->main_window), draw);
183 status = cairo_surface_write_to_png(surf, fpath);
184 if (status != CAIRO_STATUS_SUCCESS) {
185 g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
186 cairo_status_to_string(status));
187 }
189 }
190 cairo_destroy(draw);
191 }
192 // Cleanup
193 cairo_surface_destroy(surf);
194 g_free(fpath);
195 g_free(filename);
196 g_free(timestmp);
197 g_date_time_unref(now);
198}
199
201 if (state->prompt) {
202 const char *str = mode_get_display_name(state->sw);
203 textbox_text(state->prompt, str);
204 }
205}
206
207extern GList *list_of_warning_msgs;
209 if (state->mesg_box == NULL) {
210 return;
211 }
212 char *msg = mode_get_message(state->sw);
213 if (msg || list_of_warning_msgs) {
215
216 GString *emesg = g_string_new(msg);
218 if (msg) {
219 g_string_append_c(emesg, '\n');
220 }
221 g_string_append(
222 emesg, "The following warnings were detected when starting rofi:\n");
223 GList *iter = g_list_first(list_of_warning_msgs);
224 int index = 0;
225 for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
226 GString *in_msg = (GString *)(iter->data);
227 g_string_append(emesg, "\n\n");
228 g_string_append(emesg, in_msg->str);
229 index++;
230 }
231 if (g_list_length(iter) > 1) {
232 g_string_append_printf(emesg, "\nThere are <b>%u</b> more errors.",
233 g_list_length(iter) - 1);
234 }
235 }
236 textbox_text(state->mesg_tb, emesg->str);
238 g_string_free(emesg, TRUE);
239 g_free(msg);
240 } else {
242 }
243}
244
245static void rofi_view_take_action(const char *name) {
246 ThemeWidget *wid = rofi_config_find_widget(name, NULL, TRUE);
247 if (wid) {
249 Property *p = rofi_theme_find_property(wid, P_STRING, "action", TRUE);
250 if (p != NULL && p->type == P_STRING) {
251 const char *action = p->value.s;
252 guint id = key_binding_get_action_from_name(action);
253 if (id != UINT32_MAX) {
255 } else {
256 g_warning("Failed to parse keybinding: %s\r\n", action);
257 }
258 }
259 }
260}
261static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data) {
262 CacheState.user_timeout = 0;
263 rofi_view_take_action("timeout");
264 return G_SOURCE_REMOVE;
265}
266
267static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data) {
268 if (CacheState.user_timeout > 0) {
269 g_source_remove(CacheState.user_timeout);
270 CacheState.user_timeout = 0;
271 }
272 {
274 ThemeWidget *wid = rofi_config_find_widget("timeout", NULL, TRUE);
275 if (wid) {
277 Property *p = rofi_theme_find_property(wid, P_INTEGER, "delay", TRUE);
278 if (p != NULL && p->type == P_INTEGER && p->value.i > 0) {
279 int delay = p->value.i;
280 CacheState.user_timeout =
281 g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);
282 } else {
283 Property *prop = rofi_theme_find_property(wid, P_DOUBLE, "delay", TRUE);
284 if (prop != NULL && prop->type == P_DOUBLE && prop->value.f > 0.01) {
285 double delay = prop->value.f;
286 CacheState.user_timeout =
287 g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);
288 }
289 }
290 }
291 }
292}
293
295 state->quit = FALSE;
296 state->retv = MENU_CANCEL;
297}
298
300
302 if (state == current_active_menu) {
304 } else if (state) {
305 g_queue_remove(&(CacheState.views), state);
306 }
307}
309 if (current_active_menu != NULL && state != NULL) {
310 g_queue_push_head(&(CacheState.views), current_active_menu);
311 // TODO check.
312 current_active_menu = state;
313 g_debug("stack view.");
316 return;
317 } else if (state == NULL && !g_queue_is_empty(&(CacheState.views))) {
318 g_debug("pop view.");
319 current_active_menu = g_queue_pop_head(&(CacheState.views));
322 return;
323 }
324 g_assert((current_active_menu == NULL && state != NULL) ||
325 (current_active_menu != NULL && state == NULL));
326 current_active_menu = state;
328}
329
331 unsigned int selected_line) {
332 state->selected_line = selected_line;
333 // Find the line.
334 unsigned int selected = 0;
335 for (unsigned int i = 0; ((state->selected_line)) < UINT32_MAX && !selected &&
336 i < state->filtered_lines;
337 i++) {
338 if (state->line_map[i] == (state->selected_line)) {
339 selected = i;
340 break;
341 }
342 }
343 listview_set_selected(state->list_view, selected);
344#ifdef ENABLE_XCB
345 if (config.backend == DISPLAY_XCB) {
346 // Clear the window and force an expose event resulting in a redraw.
347 xcb_clear_area(xcb->connection, 1, CacheState.main_window, 0, 0, 1, 1);
348 xcb_flush(xcb->connection);
349 }
350#endif
351}
352
354 if (state->tokens) {
356 state->tokens = NULL;
357 }
358 // Do this here?
359 // Wait for final release?
361
362 g_free(state->line_map);
363 g_free(state->distance);
364 // Free the switcher boxes.
365 // When state is free'ed we should no longer need these.
366 g_free(state->modes);
367 state->num_modes = 0;
368 g_free(state);
369}
370
372 return state->retv;
373}
374
375unsigned int rofi_view_get_selected_line(const RofiViewState *state) {
376 return state->selected_line;
377}
378
379unsigned int rofi_view_get_next_position(const RofiViewState *state) {
380 unsigned int next_pos = state->selected_line;
381 unsigned int selected = listview_get_selected(state->list_view);
382 if ((selected + 1) < state->num_lines) {
383 (next_pos) = state->line_map[selected + 1];
384 }
385 return next_pos;
386}
387
388unsigned int rofi_view_get_completed(const RofiViewState *state) {
389 return state->quit;
390}
391
392const char *rofi_view_get_user_input(const RofiViewState *state) {
393 if (state->text) {
394 return state->text->text;
395 }
396 return NULL;
397}
398
405 return g_malloc0(sizeof(RofiViewState));
406}
407
411typedef struct _thread_state_view {
414
416 GCond *cond;
418 GMutex *mutex;
420 unsigned int *acount;
421
425 unsigned int start;
427 unsigned int stop;
429 unsigned int count;
430
432 const char *pattern;
434 glong plen;
442static void rofi_view_call_thread(gpointer data, gpointer user_data) {
443 thread_state *t = (thread_state *)data;
444 t->callback(t, user_data);
445}
446
448 G_GNUC_UNUSED gpointer user_data) {
450 for (unsigned int i = t->start; i < t->stop; i++) {
451 int match = mode_token_match(t->state->sw, t->state->tokens, i);
452 // If each token was matched, add it to list.
453 if (match) {
454 t->state->line_map[t->start + t->count] = i;
455 if (config.sort) {
456 // This is inefficient, need to fix it.
457 char *str = mode_get_completion(t->state->sw, i);
458 glong slen = g_utf8_strlen(str, -1);
459 switch (config.sorting_method_enum) {
460 case SORT_FZF:
462 t->pattern, t->plen, str, slen, t->state->case_sensitive);
463 break;
464 case SORT_NORMAL:
465 default:
466 t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen,
468 break;
469 }
470 g_free(str);
471 }
472 t->count++;
473 }
474 }
475 if (t->acount != NULL) {
476 g_mutex_lock(t->mutex);
477 (*(t->acount))--;
478 g_cond_signal(t->cond);
479 g_mutex_unlock(t->mutex);
480 }
481}
482
484 if (CacheState.entry_history_enable == FALSE) {
485 return;
486 }
487 CacheState.entry_history = NULL;
488 CacheState.entry_history_index = 0;
489 CacheState.entry_history_length = 0;
490
491 gchar *path = g_build_filename(cache_dir, "rofi-entry-history.txt", NULL);
492 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
493 FILE *fp = fopen(path, "r");
494 if (fp) {
495 char *line = NULL;
496 size_t len = 0;
497 ssize_t nread;
498 while ((nread = getline(&line, &len, fp)) != -1) {
499 CacheState.entry_history = g_realloc(
500 CacheState.entry_history,
501 sizeof(EntryHistoryIndex) * (CacheState.entry_history_length + 1));
502 if (line[nread - 1] == '\n') {
503 line[nread - 1] = '\0';
504 nread--;
505 }
506 CacheState.entry_history[CacheState.entry_history_length].string =
507 g_strdup(line);
508 CacheState.entry_history[CacheState.entry_history_length].index =
509 strlen(line);
510 CacheState.entry_history_length++;
511 CacheState.entry_history_index++;
512 }
513 free(line);
514 fclose(fp);
515 }
516 }
517 g_free(path);
518 CacheState.entry_history = g_realloc(
519 CacheState.entry_history,
520 sizeof(EntryHistoryIndex) * (CacheState.entry_history_length + 1));
521 CacheState.entry_history[CacheState.entry_history_length].string =
522 g_strdup("");
523 CacheState.entry_history[CacheState.entry_history_length].index = 0;
524 CacheState.entry_history_length++;
525}
527 if (CacheState.entry_history_enable == FALSE) {
528 return;
529 }
530 if (CacheState.entry_history_length > 0) {
531 // History max.
532 int max_history = 20;
533 ThemeWidget *wid = rofi_config_find_widget("entry", NULL, TRUE);
534 if (wid) {
535 Property *p =
536 rofi_theme_find_property(wid, P_INTEGER, "max-history", TRUE);
537 if (p != NULL && p->type == P_INTEGER) {
538 max_history = p->value.i;
539 }
540 }
541 gchar *path = g_build_filename(cache_dir, "rofi-entry-history.txt", NULL);
542 g_debug("Entry filename output: '%s'", path);
543 FILE *fp = fopen(path, "w");
544 if (fp) {
545 gssize start = MAX(0, (CacheState.entry_history_length - max_history));
546 for (gssize i = start; i < CacheState.entry_history_length; i++) {
547 if (strlen(CacheState.entry_history[i].string) > 0) {
548 fprintf(fp, "%s\n", CacheState.entry_history[i].string);
549 }
550 }
551 fclose(fp);
552 }
553 g_free(path);
554 }
555 // Cleanups.
556 if (CacheState.entry_history != NULL) {
557 for (ssize_t i = 0; i < CacheState.entry_history_length; i++) {
558 g_free(CacheState.entry_history[i].string);
559 }
560 g_free(CacheState.entry_history);
561 CacheState.entry_history = NULL;
562 CacheState.entry_history_length = 0;
563 CacheState.entry_history_index = 0;
564 }
565}
566
570
577 if (state->filtered_lines == 1) {
578 state->retv = MENU_OK;
579 (state->selected_line) =
581 state->quit = 1;
582 return;
583 }
584
585 // Double tab!
586 if (state->filtered_lines == 0 && ROW_TAB == state->prev_action) {
587 state->retv = MENU_NEXT;
588 (state->selected_line) = 0;
589 state->quit = TRUE;
590 } else {
592 }
593 state->prev_action = ROW_TAB;
594}
595
600inline static void rofi_view_nav_row_select(RofiViewState *state) {
601 if (state->list_view == NULL) {
602 return;
603 }
604 unsigned int selected = listview_get_selected(state->list_view);
605 // If a valid item is selected, return that..
606 if (selected < state->filtered_lines) {
607 char *str = mode_get_completion(state->sw, state->line_map[selected]);
608 textbox_text(state->text, str);
609 g_free(str);
611 state->refilter = TRUE;
612 }
613}
614
620inline static void rofi_view_nav_first(RofiViewState *state) {
621 // state->selected = 0;
623}
624
630inline static void rofi_view_nav_last(RofiViewState *state) {
631 // If no lines, do nothing.
632 if (state->filtered_lines == 0) {
633 return;
634 }
635 // state->selected = state->filtered_lines - 1;
637}
638static void selection_changed_user_callback(unsigned int index,
639 RofiViewState *state) {
640 if (config.on_selection_changed == NULL)
641 return;
642
643 int fstate = 0;
644 char *text = mode_get_display_value(state->sw, state->line_map[index],
645 &fstate, NULL, TRUE);
646 char **args = NULL;
647 int argv = 0;
648 helper_parse_setup(config.on_selection_changed, &args, &argv, "{entry}", text,
649 (char *)0);
650 if (args != NULL)
651 helper_execute(NULL, args, "", config.on_selection_changed, NULL);
652 g_free(text);
653}
654static void selection_changed_callback(G_GNUC_UNUSED listview *lv,
655 unsigned int index, void *udata) {
656 RofiViewState *state = (RofiViewState *)udata;
657 if (index < state->filtered_lines) {
658 if (state->previous_line != state->line_map[index]) {
660 state->previous_line = state->line_map[index];
661 }
662 }
663 if (state->tb_current_entry) {
664 if (index < state->filtered_lines) {
665 int fstate = 0;
666 char *text = mode_get_display_value(state->sw, state->line_map[index],
667 &fstate, NULL, TRUE);
668 textbox_text(state->tb_current_entry, text);
669 g_free(text);
670 } else {
671 textbox_text(state->tb_current_entry, "");
672 }
673 }
674 if (state->icon_current_entry) {
675 if (index < state->filtered_lines) {
676 int icon_height =
678 WIDGET(state->icon_current_entry)->w);
679 cairo_surface_t *surf_icon =
680 mode_get_icon(state->sw, state->line_map[index], icon_height);
681 icon_set_surface(state->icon_current_entry, surf_icon);
682 } else {
684 }
685 }
686}
687static void update_callback(textbox *t, icon *ico, unsigned int index,
688 void *udata, TextBoxFontType *type, gboolean full) {
689 RofiViewState *state = (RofiViewState *)udata;
690 if (full) {
691 GList *add_list = NULL;
692 int fstate = 0;
693 char *text = mode_get_display_value(state->sw, state->line_map[index],
694 &fstate, &add_list, TRUE);
695 (*type) |= fstate;
696
697 if (ico) {
698 int icon_height = widget_get_desired_height(WIDGET(ico), WIDGET(ico)->w);
699 cairo_surface_t *surf_icon =
700 mode_get_icon(state->sw, state->line_map[index], icon_height);
701 icon_set_surface(ico, surf_icon);
702 }
703 if (t) {
704 // TODO needed for markup.
705 textbox_font(t, *type);
706 // Move into list view.
707 textbox_text(t, text);
708 PangoAttrList *list = textbox_get_pango_attributes(t);
709 if (list != NULL) {
710 pango_attr_list_ref(list);
711 } else {
712 list = pango_attr_list_new();
713 }
714
715 if (state->tokens) {
717 {0.0, 0.0, 0.0, 0.0}};
718 th = rofi_theme_get_highlight(WIDGET(t), "highlight", th);
720 textbox_get_visible_text(t), list);
721 }
722 for (GList *iter = g_list_first(add_list); iter != NULL;
723 iter = g_list_next(iter)) {
724 pango_attr_list_insert(list, (PangoAttribute *)(iter->data));
725 }
727 pango_attr_list_unref(list);
728 }
729
730 g_list_free(add_list);
731 g_free(text);
732 } else {
733 // Never called.
734 int fstate = 0;
735 mode_get_display_value(state->sw, state->line_map[index], &fstate, NULL,
736 FALSE);
737 (*type) |= fstate;
738 // TODO needed for markup.
739 textbox_font(t, *type);
740 }
741}
746
748 g_free(state->line_map);
749 g_free(state->distance);
750 state->num_lines = mode_get_num_entries(state->sw);
751 state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));
752 state->distance = g_malloc0_n(state->num_lines, sizeof(int));
755}
756
757static gboolean rofi_view_refilter_real(RofiViewState *state) {
758 CacheState.refilter_timeout = 0;
759 CacheState.refilter_timeout_count = 0;
760 if (state->sw == NULL) {
761 return G_SOURCE_REMOVE;
762 }
763 GTimer *timer = g_timer_new();
764 TICK_N("Filter start");
765 if (state->reload) {
767 state->reload = FALSE;
768 }
769 TICK_N("Filter reload rows");
770 if (state->tokens) {
772 state->tokens = NULL;
773 }
774 TICK_N("Filter tokenize");
775 if (state->text && strlen(state->text->text) > 0) {
776
777 listview_set_filtered(state->list_view, TRUE);
778 unsigned int j = 0;
779 gchar *pattern = mode_preprocess_input(state->sw, state->text->text);
780 glong plen = pattern ? g_utf8_strlen(pattern, -1) : 0;
782 state->tokens = helper_tokenize(pattern, state->case_sensitive);
783
784 if (config.case_smart && state->case_indicator) {
786 }
794 unsigned int nt = MAX(1, state->num_lines / 500);
795 // Limit the number of jobs, it could cause stack overflow if we don´t
796 // limit.
797 nt = MIN(nt, config.threads * 4);
798 thread_state_view states[nt];
799 GCond cond;
800 GMutex mutex;
801 g_mutex_init(&mutex);
802 g_cond_init(&cond);
803 unsigned int count = nt;
804 unsigned int steps = (state->num_lines + nt) / nt;
805 for (unsigned int i = 0; i < nt; i++) {
806 states[i].state = state;
807 states[i].start = i * steps;
808 states[i].stop = MIN(state->num_lines, (i + 1) * steps);
809 states[i].count = 0;
810 states[i].cond = &cond;
811 states[i].mutex = &mutex;
812 states[i].acount = &count;
813 states[i].plen = plen;
814 states[i].pattern = pattern;
815 states[i].st.callback = filter_elements;
816 states[i].st.free = NULL;
817 states[i].st.priority = G_PRIORITY_HIGH;
818 if (i > 0) {
819 g_thread_pool_push(tpool, &states[i], NULL);
820 }
821 }
822 // Run one in this thread.
823 rofi_view_call_thread(&states[0], NULL);
824 // No need to do this with only one thread.
825 if (nt > 1) {
826 g_mutex_lock(&mutex);
827 while (count > 0) {
828 g_cond_wait(&cond, &mutex);
829 }
830 g_mutex_unlock(&mutex);
831 }
832 g_cond_clear(&cond);
833 g_mutex_clear(&mutex);
834 for (unsigned int i = 0; i < nt; i++) {
835 if (j != states[i].start) {
836 memmove(&(state->line_map[j]), &(state->line_map[states[i].start]),
837 sizeof(unsigned int) * (states[i].count));
838 }
839 j += states[i].count;
840 }
841 if (config.sort) {
842 g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
843 state->distance);
844 }
845
846 // Cleanup + bookkeeping.
847 state->filtered_lines = j;
848 g_free(pattern);
849
850 double elapsed = g_timer_elapsed(timer, NULL);
851
852 CacheState.max_refilter_time = elapsed;
853 } else {
854 listview_set_filtered(state->list_view, FALSE);
855 for (unsigned int i = 0; i < state->num_lines; i++) {
856 state->line_map[i] = i;
857 }
858 state->filtered_lines = state->num_lines;
859 }
860 TICK_N("Filter matching done");
862
863 if (state->tb_filtered_rows) {
864 char *r = g_strdup_printf("%u", state->filtered_lines);
866 g_free(r);
867 }
868 if (state->tb_total_rows) {
869 char *r = g_strdup_printf("%u", state->num_lines);
870 textbox_text(state->tb_total_rows, r);
871 g_free(r);
872 }
873 TICK_N("Update filter lines");
874
875 if (config.auto_select == TRUE && state->filtered_lines == 1 &&
876 state->num_lines > 1) {
877 (state->selected_line) =
879 state->retv = MENU_OK;
880 state->quit = TRUE;
881 }
882
883 // Size the window.
884 int height = rofi_view_calculate_window_height(state);
885 if (height != state->height) {
886 state->height = height;
889 g_debug("Resize based on re-filter");
890 }
891 TICK_N("Filter resize window based on window ");
892 state->refilter = FALSE;
893 TICK_N("Filter done");
894 rofi_view_update(state, TRUE);
895
896 g_timer_destroy(timer);
897 return G_SOURCE_REMOVE;
898}
900 CacheState.refilter_timeout_count++;
901 if (CacheState.refilter_timeout != 0) {
902
903 g_source_remove(CacheState.refilter_timeout);
904 CacheState.refilter_timeout = 0;
905 }
906 if (CacheState.max_refilter_time > (config.refilter_timeout_limit / 1000.0) &&
907 state->text && strlen(state->text->text) > 0 &&
908 CacheState.refilter_timeout_count < 25) {
909 if (CacheState.delayed_mode == FALSE) {
910 g_warning(
911 "Filtering took %f seconds ( %f ), switching to delayed filter\n",
912 CacheState.max_refilter_time, config.refilter_timeout_limit / 1000.0);
913 CacheState.delayed_mode = TRUE;
914 }
915 CacheState.refilter_timeout =
916 g_timeout_add(200, (GSourceFunc)rofi_view_refilter_real, state);
917 } else {
918 if (CacheState.delayed_mode == TRUE && state->text &&
919 strlen(state->text->text) > 0 &&
920 CacheState.refilter_timeout_count < 25) {
921 g_warning(
922 "Filtering took %f seconds , switching back to instant filter\n",
923 CacheState.max_refilter_time);
924 CacheState.delayed_mode = FALSE;
925 }
927 }
928}
930 if (CacheState.refilter_timeout != 0) {
931 g_source_remove(CacheState.refilter_timeout);
932 CacheState.refilter_timeout = 0;
933 }
934 if (state->refilter) {
936 }
937}
938
943void process_result(RofiViewState *state);
945 if (state && state->finalize != NULL) {
946 state->finalize(state);
947 }
948}
949
954static void rofi_view_input_changed(void) {
955 rofi_view_take_action("inputchange");
956
958 if (CacheState.entry_history_enable && state) {
959 if (CacheState.entry_history[CacheState.entry_history_index].string !=
960 NULL) {
961 g_free(CacheState.entry_history[CacheState.entry_history_index].string);
962 }
963 CacheState.entry_history[CacheState.entry_history_index].string =
964 textbox_get_text(state->text);
965 CacheState.entry_history[CacheState.entry_history_index].index =
966 textbox_get_cursor(state->text);
967 }
968}
969
970#ifdef ENABLE_WAYLAND
971static void rofi_view_clipboard_callback(char *clipboard_data, G_GNUC_UNUSED void *user_data) {
973 if (clipboard_data != NULL) {
974 if (state != NULL) {
976 }
977 g_free(clipboard_data);
978 }
979}
980#endif
981
984 switch (action) {
985 // Handling of paste
986 case PASTE_PRIMARY:
987#ifdef ENABLE_XCB
988 if (config.backend == DISPLAY_XCB) {
989 xcb_convert_selection(xcb->connection, CacheState.main_window,
990 XCB_ATOM_PRIMARY, xcb->ewmh.UTF8_STRING,
991 xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
992 xcb_flush(xcb->connection);
993 }
994#endif
995#ifdef ENABLE_WAYLAND
996 if (config.backend == DISPLAY_WAYLAND) {
997 display_get_clipboard_data(CLIPBOARD_PRIMARY, rofi_view_clipboard_callback, NULL);
998 }
999#endif
1000 break;
1001 case PASTE_SECONDARY:
1002#ifdef ENABLE_XCB
1003 if (config.backend == DISPLAY_XCB) {
1004 xcb_convert_selection(xcb->connection, CacheState.main_window,
1005 netatoms[CLIPBOARD], xcb->ewmh.UTF8_STRING,
1006 xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1007 xcb_flush(xcb->connection);
1008 }
1009#endif
1010#ifdef ENABLE_WAYLAND
1011 if (config.backend == DISPLAY_WAYLAND) {
1012 display_get_clipboard_data(CLIPBOARD_DEFAULT, rofi_view_clipboard_callback, NULL);
1013 }
1014#endif
1015 break;
1016 case COPY_SECONDARY: {
1017 char *data = NULL;
1018 unsigned int selected = listview_get_selected(state->list_view);
1019 if (selected < state->filtered_lines) {
1020 data = mode_get_completion(state->sw, state->line_map[selected]);
1021 } else if (state->text && state->text->text) {
1022 data = g_strdup(state->text->text);
1023 }
1024 if (data) {
1025#ifdef ENABLE_XCB
1026 if (config.backend == DISPLAY_XCB) {
1028 xcb_set_selection_owner(xcb->connection, CacheState.main_window,
1029 netatoms[CLIPBOARD], XCB_CURRENT_TIME);
1030 xcb_flush(xcb->connection);
1031 }
1032#endif
1033#ifdef ENABLE_WAYLAND
1034 if (config.backend == DISPLAY_WAYLAND) {
1035 // TODO
1036 }
1037#endif
1038 }
1039 } break;
1040 case SCREENSHOT:
1042 break;
1043 case CHANGE_ELLIPSIZE:
1044 if (state->list_view) {
1046 }
1047 break;
1048 case TOGGLE_SORT:
1049 if (state->case_indicator != NULL) {
1050 config.sort = !config.sort;
1051 state->refilter = TRUE;
1053 }
1054 break;
1055 case MODE_PREVIOUS:
1056 state->retv = MENU_PREVIOUS;
1057 (state->selected_line) = 0;
1058 state->quit = TRUE;
1059 break;
1060 // Menu navigation.
1061 case MODE_NEXT:
1062 state->retv = MENU_NEXT;
1063 (state->selected_line) = 0;
1064 state->quit = TRUE;
1065 break;
1066 case MODE_COMPLETE: {
1067 unsigned int selected = listview_get_selected(state->list_view);
1068 state->selected_line = UINT32_MAX;
1069 if (selected < state->filtered_lines) {
1070 state->selected_line = state->line_map[selected];
1071 }
1072 state->retv = MENU_COMPLETE;
1073 state->quit = TRUE;
1074 break;
1075 }
1076 // Toggle case sensitivity.
1078 if (state->case_indicator != NULL) {
1079 config.case_sensitive = !config.case_sensitive;
1080 (state->selected_line) = 0;
1081 state->refilter = TRUE;
1083 }
1084 break;
1085 // Special delete entry command.
1086 case DELETE_ENTRY: {
1087 unsigned int selected = listview_get_selected(state->list_view);
1088 if (selected < state->filtered_lines) {
1089 (state->selected_line) = state->line_map[selected];
1090 state->retv = MENU_ENTRY_DELETE;
1091 state->quit = TRUE;
1092 }
1093 break;
1094 }
1095 case SELECT_ELEMENT_1:
1096 case SELECT_ELEMENT_2:
1097 case SELECT_ELEMENT_3:
1098 case SELECT_ELEMENT_4:
1099 case SELECT_ELEMENT_5:
1100 case SELECT_ELEMENT_6:
1101 case SELECT_ELEMENT_7:
1102 case SELECT_ELEMENT_8:
1103 case SELECT_ELEMENT_9:
1104 case SELECT_ELEMENT_10: {
1105 unsigned int index = action - SELECT_ELEMENT_1;
1106 if (index < state->filtered_lines) {
1107 state->selected_line = state->line_map[index];
1108 state->retv = MENU_OK;
1109 state->quit = TRUE;
1110 }
1111 break;
1112 }
1113 case CUSTOM_1:
1114 case CUSTOM_2:
1115 case CUSTOM_3:
1116 case CUSTOM_4:
1117 case CUSTOM_5:
1118 case CUSTOM_6:
1119 case CUSTOM_7:
1120 case CUSTOM_8:
1121 case CUSTOM_9:
1122 case CUSTOM_10:
1123 case CUSTOM_11:
1124 case CUSTOM_12:
1125 case CUSTOM_13:
1126 case CUSTOM_14:
1127 case CUSTOM_15:
1128 case CUSTOM_16:
1129 case CUSTOM_17:
1130 case CUSTOM_18:
1131 case CUSTOM_19: {
1132 state->selected_line = UINT32_MAX;
1133 unsigned int selected = listview_get_selected(state->list_view);
1134 if (selected < state->filtered_lines) {
1135 (state->selected_line) = state->line_map[selected];
1136 }
1137 state->retv = MENU_CUSTOM_COMMAND | ((action - CUSTOM_1) & MENU_LOWER_MASK);
1138 state->quit = TRUE;
1139 break;
1140 }
1141 // If you add a binding here, make sure to add it to
1142 // rofi_view_keyboard_navigation too
1143 case CANCEL:
1144 state->retv = MENU_CANCEL;
1145 state->quit = TRUE;
1146 break;
1147 case ELEMENT_NEXT:
1149 break;
1150 case ELEMENT_PREV:
1152 break;
1153 case ROW_UP:
1154 listview_nav_up(state->list_view);
1155 break;
1156 case ROW_TAB:
1157 rofi_view_nav_row_tab(state);
1158 break;
1159 case ROW_DOWN:
1161 break;
1162 case ROW_LEFT:
1164 break;
1165 case ROW_RIGHT:
1167 break;
1168 case PAGE_PREV:
1170 break;
1171 case PAGE_NEXT:
1173 break;
1174 case ROW_FIRST:
1175 rofi_view_nav_first(state);
1176 break;
1177 case ROW_LAST:
1178 rofi_view_nav_last(state);
1179 break;
1180 case ROW_SELECT:
1182 break;
1183 // If you add a binding here, make sure to add it to textbox_keybinding too
1184 case MOVE_CHAR_BACK: {
1185 if (textbox_keybinding(state->text, action) == 0) {
1187 }
1188 break;
1189 }
1190 case MOVE_CHAR_FORWARD: {
1191 if (textbox_keybinding(state->text, action) == 0) {
1193 }
1194 break;
1195 }
1196 case CLEAR_LINE:
1197 case MOVE_FRONT:
1198 case MOVE_END:
1199 case REMOVE_TO_EOL:
1200 case REMOVE_TO_SOL:
1201 case REMOVE_WORD_BACK:
1204 case MOVE_WORD_BACK:
1205 case MOVE_WORD_FORWARD:
1206 case REMOVE_CHAR_BACK: {
1207 int rc = textbox_keybinding(state->text, action);
1208 if (rc == 1) {
1209 // Entry changed.
1210 state->refilter = TRUE;
1212 } else if (rc == 2) {
1213 // Movement.
1214 }
1215 break;
1216 }
1217 case ACCEPT_ALT: {
1219 unsigned int selected = listview_get_selected(state->list_view);
1220 state->selected_line = UINT32_MAX;
1221 if (selected < state->filtered_lines) {
1222 (state->selected_line) = state->line_map[selected];
1223 state->retv = MENU_OK;
1224 } else {
1225 // Nothing entered and nothing selected.
1226 state->retv = MENU_CUSTOM_INPUT;
1227 }
1228 state->retv |= MENU_CUSTOM_ACTION;
1229 state->quit = TRUE;
1230 break;
1231 }
1232 case ACCEPT_CUSTOM: {
1234 state->selected_line = UINT32_MAX;
1235 state->retv = MENU_CUSTOM_INPUT;
1236 state->quit = TRUE;
1237 break;
1238 }
1239 case ACCEPT_CUSTOM_ALT: {
1241 state->selected_line = UINT32_MAX;
1243 state->quit = TRUE;
1244 break;
1245 }
1246 case ACCEPT_ENTRY: {
1248 // If a valid item is selected, return that..
1249 unsigned int selected = listview_get_selected(state->list_view);
1250 state->selected_line = UINT32_MAX;
1251 if (selected < state->filtered_lines) {
1252 (state->selected_line) = state->line_map[selected];
1253 state->retv = MENU_OK;
1254 } else {
1255 // Nothing entered and nothing selected.
1256 state->retv = MENU_CUSTOM_INPUT;
1257 }
1258 state->quit = TRUE;
1259 break;
1260 }
1261 case ENTRY_HISTORY_DOWN: {
1262 if (CacheState.entry_history_enable && state->text) {
1263 CacheState.entry_history[CacheState.entry_history_index].index =
1264 textbox_get_cursor(state->text);
1265 if (CacheState.entry_history_index > 0) {
1266 CacheState.entry_history_index--;
1267 }
1268 if (state->text) {
1270 state->text,
1271 CacheState.entry_history[CacheState.entry_history_index].string);
1273 state->text,
1274 CacheState.entry_history[CacheState.entry_history_index].index);
1275 state->refilter = TRUE;
1276 }
1277 }
1278 break;
1279 }
1280 case ENTRY_HISTORY_UP: {
1281 if (CacheState.entry_history_enable && state->text) {
1282 if (CacheState.entry_history[CacheState.entry_history_index].string !=
1283 NULL) {
1284 g_free(CacheState.entry_history[CacheState.entry_history_index].string);
1285 }
1286 CacheState.entry_history[CacheState.entry_history_index].string =
1287 textbox_get_text(state->text);
1288 CacheState.entry_history[CacheState.entry_history_index].index =
1289 textbox_get_cursor(state->text);
1290 // Don't create up if current is empty.
1291 if (strlen(
1292 CacheState.entry_history[CacheState.entry_history_index].string) >
1293 0) {
1294 CacheState.entry_history_index++;
1295 if (CacheState.entry_history_index >= CacheState.entry_history_length) {
1296 CacheState.entry_history =
1297 g_realloc(CacheState.entry_history,
1298 sizeof(EntryHistoryIndex) *
1299 (CacheState.entry_history_length + 1));
1300 CacheState.entry_history[CacheState.entry_history_length].string =
1301 g_strdup("");
1302 CacheState.entry_history[CacheState.entry_history_length].index = 0;
1303 CacheState.entry_history_length++;
1304 }
1305 }
1307 state->text,
1308 CacheState.entry_history[CacheState.entry_history_index].string);
1310 state->text,
1311 CacheState.entry_history[CacheState.entry_history_index].index);
1312 state->refilter = TRUE;
1313 }
1314 break;
1315 }
1316 case MATCHER_UP:
1318 rofi_view_refilter(state);
1320 break;
1321 case MATCHER_DOWN:
1323 rofi_view_refilter(state);
1325 break;
1326 }
1327}
1328
1330 guint action) {
1331 switch (scope) {
1332 case SCOPE_GLOBAL:
1333 return TRUE;
1339 gint x = state->mouse.x, y = state->mouse.y;
1341 (WidgetType)scope, x, y);
1342 if (target == NULL) {
1343 return FALSE;
1344 }
1345 widget_xy_to_relative(target, &x, &y);
1346 switch (widget_check_action(target, action, x, y)) {
1348 return FALSE;
1352 return TRUE;
1353 }
1354 break;
1355 }
1356 }
1357 return FALSE;
1358}
1359
1361 guint action) {
1363 switch (scope) {
1364 case SCOPE_GLOBAL:
1366 return;
1372 gint x = state->mouse.x, y = state->mouse.y;
1373 // If we already captured a motion, always forward action to this widget.
1374 widget *target = state->mouse.motion_target;
1375 // If we have not a previous captured motion, lookup widget.
1376 if (target == NULL) {
1378 (WidgetType)scope, x, y);
1379 }
1380 if (target == NULL) {
1381 return;
1382 }
1383 widget_xy_to_relative(target, &x, &y);
1384 switch (widget_trigger_action(target, action, x, y)) {
1386 return;
1388 target = NULL;
1391 state->mouse.motion_target = target;
1394 return;
1395 }
1396 break;
1397 }
1398 }
1399}
1400
1401void rofi_view_handle_text(RofiViewState *state, char *text) {
1402 if (textbox_append_text(state->text, text, strlen(text))) {
1403 state->refilter = TRUE;
1405 }
1406}
1407
1408#if 0
1410{
1411 switch ( type )
1412 {
1414 return CURSOR_DEFAULT;
1415
1417 return CURSOR_POINTER;
1418
1419 case ROFI_CURSOR_TEXT:
1420 return CURSOR_TEXT;
1421 }
1422
1423 return CURSOR_DEFAULT;
1424}
1425#endif
1426
1428 gint y) {
1430 WIDGET_TYPE_UNKNOWN, x, y);
1431
1432 return target != NULL ? target->cursor_type : ROFI_CURSOR_DEFAULT;
1433}
1434
1436 gboolean find_mouse_target) {
1437 state->mouse.x = x;
1438 state->mouse.y = y;
1439
1441
1443
1444 if (find_mouse_target) {
1447
1448 if (target != NULL) {
1449 state->mouse.motion_target = target;
1450 }
1451 }
1452
1453 if (state->mouse.motion_target != NULL) {
1456
1457 if (find_mouse_target) {
1458 state->mouse.motion_target = NULL;
1459 }
1460 }
1461}
1462
1464 if (state->retv & MENU_OK) {
1465 if (config.on_entry_accepted == NULL)
1466 return;
1467 int fstate = 0;
1468 unsigned int selected = listview_get_selected(state->list_view);
1469 // TODO: handle custom text
1470 if (selected >= state->filtered_lines)
1471 return;
1472 // Pass selected text to custom command
1473 char *text = mode_get_display_value(state->sw, state->line_map[selected],
1474 &fstate, NULL, TRUE);
1475 char **args = NULL;
1476 int argv = 0;
1477 helper_parse_setup(config.on_entry_accepted, &args, &argv, "{entry}", text,
1478 (char *)0);
1479 if (args != NULL)
1480 helper_execute(NULL, args, "", config.on_entry_accepted, NULL);
1481 g_free(text);
1482 } else if (state->retv & MENU_CANCEL) {
1483 if (config.on_menu_canceled == NULL)
1484 return;
1485 helper_execute_command(NULL, config.on_menu_canceled, FALSE, NULL);
1486 } else if (state->retv & MENU_NEXT || state->retv & MENU_PREVIOUS ||
1487 state->retv & MENU_QUICK_SWITCH || state->retv & MENU_COMPLETE) {
1488 if (config.on_mode_changed == NULL)
1489 return;
1490 // TODO: pass mode name to custom command
1491 helper_execute_command(NULL, config.on_mode_changed, FALSE, NULL);
1492 }
1493}
1494
1496 if (rofi_view_get_completed(state)) {
1497 // Exec custom user commands
1499 // This menu is done.
1500 rofi_view_finalize(state);
1501 // If there a state. (for example error) reload it.
1502 state = rofi_view_get_active();
1503
1504 // cleanup, if no more state to display.
1505 if (state == NULL) {
1506 // Quit main-loop.
1508 return;
1509 }
1510 }
1511
1512 // Update if requested.
1513 if (state->refilter) {
1514 rofi_view_refilter(state);
1515 }
1516 rofi_view_update(state, TRUE);
1517 return;
1518}
1520 widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
1521 G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
1522 RofiViewState *state = (RofiViewState *)user_data;
1523 switch (action) {
1524 case MOUSE_CLICK_DOWN: {
1525 const char *type = rofi_theme_get_string(wid, "action", NULL);
1526 if (type) {
1527 if (state->list_view) {
1528 (state->selected_line) =
1530 } else {
1531 (state->selected_line) = UINT32_MAX;
1532 }
1533 guint id = key_binding_get_action_from_name(type);
1534 if (id != UINT32_MAX) {
1536 }
1537 state->skip_absorb = TRUE;
1539 }
1540 }
1541 case MOUSE_CLICK_UP:
1542 case MOUSE_DCLICK_DOWN:
1543 case MOUSE_DCLICK_UP:
1544 break;
1545 }
1547}
1549 widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
1550 G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
1551 RofiViewState *state = (RofiViewState *)user_data;
1552 unsigned int i;
1553 for (i = 0; i < state->num_modes; i++) {
1554 if (WIDGET(state->modes[i]) == wid) {
1555 break;
1556 }
1557 }
1558 if (i == state->num_modes) {
1560 }
1561
1562 switch (action) {
1563 case MOUSE_CLICK_DOWN:
1564 state->retv = MENU_QUICK_SWITCH | (i & MENU_LOWER_MASK);
1565 state->quit = TRUE;
1566 state->skip_absorb = TRUE;
1568 case MOUSE_CLICK_UP:
1569 case MOUSE_DCLICK_DOWN:
1570 case MOUSE_DCLICK_UP:
1571 break;
1572 }
1574}
1575
1576// @TODO don't like this construction.
1577static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom,
1578 void *udata) {
1579 RofiViewState *state = (RofiViewState *)udata;
1580 state->retv = MENU_OK;
1581 if (custom) {
1582 state->retv |= MENU_CUSTOM_ACTION;
1583 }
1584 (state->selected_line) = state->line_map[listview_get_selected(lv)];
1585 // Quit
1586 state->quit = TRUE;
1587 state->skip_absorb = TRUE;
1588}
1589
1590static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget,
1591 const char *name) {
1592 char *defaults = NULL;
1593 widget *wid = NULL;
1594
1598 if (strcmp(name, "mainbox") == 0) {
1599 wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);
1600 box_add((box *)parent_widget, WIDGET(wid), TRUE);
1601 if (config.sidebar_mode) {
1602 defaults = "inputbar,message,listview,mode-switcher";
1603 } else {
1604 defaults = "inputbar,message,listview";
1605 }
1606 }
1610 else if (strcmp(name, "inputbar") == 0) {
1611 wid =
1612 (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);
1613 defaults = "prompt,entry,overlay,case-indicator";
1614 box_add((box *)parent_widget, WIDGET(wid), FALSE);
1615 }
1619 else if (strcmp(name, "prompt") == 0) {
1620 if (state->prompt != NULL) {
1621 g_error("Prompt widget can only be added once to the layout.");
1622 return;
1623 }
1624 // Prompt box.
1625 state->prompt =
1626 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1627 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1629 box_add((box *)parent_widget, WIDGET(state->prompt), FALSE);
1630 defaults = NULL;
1631 } else if (strcmp(name, "num-rows") == 0) {
1632 state->tb_total_rows =
1633 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1634 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1635 box_add((box *)parent_widget, WIDGET(state->tb_total_rows), FALSE);
1636 defaults = NULL;
1637 } else if (strcmp(name, "num-filtered-rows") == 0) {
1638 state->tb_filtered_rows =
1639 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1640 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1641 box_add((box *)parent_widget, WIDGET(state->tb_filtered_rows), FALSE);
1642 defaults = NULL;
1643 } else if (strcmp(name, "textbox-current-entry") == 0) {
1644 state->tb_current_entry =
1645 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1646 TB_MARKUP | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
1647 box_add((box *)parent_widget, WIDGET(state->tb_current_entry), FALSE);
1648 defaults = NULL;
1649 } else if (strcmp(name, "icon-current-entry") == 0) {
1650 state->icon_current_entry = icon_create(parent_widget, name);
1651 box_add((box *)parent_widget, WIDGET(state->icon_current_entry), FALSE);
1652 defaults = NULL;
1653 }
1657 else if (strcmp(name, "case-indicator") == 0) {
1658 if (state->case_indicator != NULL) {
1659 g_error("Case indicator widget can only be added once to the layout.");
1660 return;
1661 }
1662 state->case_indicator =
1663 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1664 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*", 0, 0);
1665 // Add small separator between case indicator and text box.
1666 box_add((box *)parent_widget, WIDGET(state->case_indicator), FALSE);
1668 }
1672 else if (strcmp(name, "entry") == 0) {
1673 if (state->text != NULL) {
1674 g_error("Entry textbox widget can only be added once to the layout.");
1675 return;
1676 }
1677 // Entry box
1679 tfl |= ((state->menu_flags & MENU_PASSWORD) == MENU_PASSWORD) ? TB_PASSWORD
1680 : 0;
1681 state->text = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,
1682 tfl | TB_AUTOHEIGHT, NORMAL, NULL, 0, 0);
1683 box_add((box *)parent_widget, WIDGET(state->text), TRUE);
1684 }
1688 else if (strcmp(name, "message") == 0) {
1689 if (state->mesg_box != NULL) {
1690 g_error("Message widget can only be added once to the layout.");
1691 return;
1692 }
1693 state->mesg_box = container_create(parent_widget, name);
1694 state->mesg_tb = textbox_create(
1695 WIDGET(state->mesg_box), WIDGET_TYPE_TEXTBOX_TEXT, "textbox",
1696 TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL, 0, 0);
1697 container_add(state->mesg_box, WIDGET(state->mesg_tb));
1699 box_add((box *)parent_widget, WIDGET(state->mesg_box), FALSE);
1700 }
1704 else if (strcmp(name, "listview") == 0) {
1705 if (state->list_view != NULL) {
1706 g_error("Listview widget can only be added once to the layout.");
1707 return;
1708 }
1709 state->list_view =
1710 listview_create(parent_widget, name, update_callback,
1711 page_changed_callback, state, config.element_height, 0);
1713 state->list_view, selection_changed_callback, (void *)state);
1714 box_add((box *)parent_widget, WIDGET(state->list_view), TRUE);
1715 listview_set_scroll_type(state->list_view, config.scroll_method);
1717 state->list_view, rofi_view_listview_mouse_activated_cb, state);
1718
1719 listview_set_max_lines(state->list_view, state->num_lines);
1720 }
1724 else if (strcmp(name, "mode-switcher") == 0 || strcmp(name, "sidebar") == 0) {
1725 if (state->sidebar_bar != NULL) {
1726 g_error("Mode-switcher can only be added once to the layout.");
1727 return;
1728 }
1729 state->sidebar_bar =
1730 box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);
1731 box_add((box *)parent_widget, WIDGET(state->sidebar_bar), FALSE);
1733 state->modes = g_malloc0(state->num_modes * sizeof(textbox *));
1734 for (unsigned int j = 0; j < state->num_modes; j++) {
1735 const Mode *mode = rofi_get_mode(j);
1736 state->modes[j] = textbox_create(
1737 WIDGET(state->sidebar_bar), WIDGET_TYPE_MODE_SWITCHER, "button",
1738 TB_AUTOHEIGHT, (mode == state->sw) ? HIGHLIGHT : NORMAL,
1739 mode_get_display_name(mode), 0.5, 0.5);
1740 box_add(state->sidebar_bar, WIDGET(state->modes[j]), TRUE);
1743 }
1744 } else if (g_ascii_strcasecmp(name, "overlay") == 0) {
1745 state->overlay = textbox_create(
1746 WIDGET(parent_widget), WIDGET_TYPE_TEXTBOX_TEXT, "overlay",
1747 TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, "blaat", 0.5, 0);
1748 box_add((box *)parent_widget, WIDGET(state->overlay), FALSE);
1749 widget_disable(WIDGET(state->overlay));
1750 } else if (g_ascii_strncasecmp(name, "textbox", 7) == 0) {
1751 textbox *t = textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
1752 TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0);
1753 box_add((box *)parent_widget, WIDGET(t), TRUE);
1754 } else if (g_ascii_strncasecmp(name, "button", 6) == 0) {
1755 textbox *t = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,
1756 TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0);
1757 box_add((box *)parent_widget, WIDGET(t), TRUE);
1759 state);
1760 } else if (g_ascii_strncasecmp(name, "icon", 4) == 0) {
1761 icon *t = icon_create(parent_widget, name);
1762 /* small hack to make it clickable */
1763 const char *type = rofi_theme_get_string(WIDGET(t), "action", NULL);
1764 if (type) {
1765 WIDGET(t)->type = WIDGET_TYPE_EDITBOX;
1766 }
1767 box_add((box *)parent_widget, WIDGET(t), TRUE);
1769 state);
1770 } else {
1771 wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);
1772 box_add((box *)parent_widget, WIDGET(wid), TRUE);
1773 // g_error("The widget %s does not exists. Invalid layout.", name);
1774 }
1775 if (wid) {
1776 GList *list = rofi_theme_get_list_strings(wid, "children");
1777 if (list == NULL) {
1778 if (defaults) {
1779 char **a = g_strsplit(defaults, ",", 0);
1780 for (int i = 0; a && a[i]; i++) {
1781 rofi_view_add_widget(state, wid, a[i]);
1782 }
1783 g_strfreev(a);
1784 }
1785 } else {
1786 for (const GList *iter = g_list_first(list); iter != NULL;
1787 iter = g_list_next(iter)) {
1788 rofi_view_add_widget(state, wid, (const char *)iter->data);
1789 }
1790 g_list_free_full(list, g_free);
1791 }
1792 }
1793}
1794
1795RofiViewState *rofi_view_create(Mode *sw, const char *input,
1796 MenuFlags menu_flags,
1797 void (*finalize)(RofiViewState *)) {
1798 TICK();
1800 state->menu_flags = menu_flags;
1801 state->sw = sw;
1802 state->selected_line = UINT32_MAX;
1803 state->previous_line = UINT32_MAX;
1804 state->retv = MENU_CANCEL;
1805 state->distance = NULL;
1806 state->quit = FALSE;
1807 state->skip_absorb = FALSE;
1808 // We want to filter on the first run.
1809 state->refilter = TRUE;
1810 state->finalize = finalize;
1811 state->mouse_seen = FALSE;
1812
1813 // In password mode, disable the entry history.
1814 if ((menu_flags & MENU_PASSWORD) == MENU_PASSWORD) {
1815 CacheState.entry_history_enable = FALSE;
1816 g_debug("Disable entry history, because password setup.");
1817 }
1818 if (config.disable_history) {
1819 CacheState.entry_history_enable = FALSE;
1820 g_debug("Disable entry history, because history disable flag.");
1821 }
1822 // Request the lines to show.
1823 state->num_lines = mode_get_num_entries(sw);
1824
1825 if (state->sw) {
1826 char *title =
1827 g_strdup_printf("rofi - %s", mode_get_display_name(state->sw));
1829 g_free(title);
1830 } else {
1832 }
1833 TICK_N("Startup notification");
1834
1835 // Get active monitor size.
1836 TICK_N("Get active monitor");
1837
1838 state->main_window = box_create(NULL, "window", ROFI_ORIENTATION_VERTICAL);
1839 // Get children.
1840 GList *list =
1841 rofi_theme_get_list_strings(WIDGET(state->main_window), "children");
1842 if (list == NULL) {
1843 rofi_view_add_widget(state, WIDGET(state->main_window), "mainbox");
1844 } else {
1845 for (const GList *iter = list; iter != NULL; iter = g_list_next(iter)) {
1847 (const char *)iter->data);
1848 }
1849 g_list_free_full(list, g_free);
1850 }
1851
1852 if (state->text && input) {
1853 textbox_text(state->text, input);
1854 textbox_cursor_end(state->text);
1855 }
1856
1857 // filtered list
1858 state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));
1859 state->distance = (int *)g_malloc0_n(state->num_lines, sizeof(int));
1860
1862 // Only needed when window is fixed size.
1865 }
1866
1868 // Move the window to the correct x,y position.
1871
1872 state->quit = FALSE;
1873 rofi_view_refilter(state);
1874 rofi_view_update(state, TRUE);
1875#ifdef ENABLE_XCB
1876 if (xcb->connection) {
1877 xcb_map_window(xcb->connection, CacheState.main_window);
1878 }
1879#endif
1881 rofi_view_ping_mouse(state);
1882#ifdef ENABLE_XCB
1883 if (xcb->connection) {
1884 xcb_flush(xcb->connection);
1885 }
1886#endif
1887
1889 /* When Override Redirect, the WM will not let us know we can take focus, so
1890 * just steal it */
1891 if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {
1893 }
1894
1895#ifdef ENABLE_XCB
1896 if (xcb->sncontext != NULL) {
1897 sn_launchee_context_complete(xcb->sncontext);
1898 }
1899#endif
1900 return state;
1901}
1902
1903static void rofi_error_user_callback(const char *msg) {
1904 if (config.on_menu_error == NULL)
1905 return;
1906
1907 char **args = NULL;
1908 int argv = 0;
1909 helper_parse_setup(config.on_menu_error, &args, &argv, "{error}", msg,
1910 (char *)0);
1911 if (args != NULL)
1912 helper_execute(NULL, args, "", config.on_menu_error, NULL);
1913}
1914
1915int rofi_view_error_dialog(const char *msg, int markup) {
1917 state->retv = MENU_CANCEL;
1919 state->finalize = process_result;
1920
1921 state->main_window = box_create(NULL, "window", ROFI_ORIENTATION_VERTICAL);
1922 box *new_box = box_create(WIDGET(state->main_window), "error-message",
1924 box_add(state->main_window, WIDGET(new_box), TRUE);
1925 state->text =
1926 textbox_create(WIDGET(new_box), WIDGET_TYPE_TEXTBOX_TEXT, "textbox",
1927 (TB_AUTOHEIGHT | TB_WRAP) + ((markup) ? TB_MARKUP : 0),
1928 NORMAL, (msg != NULL) ? msg : "", 0, 0);
1929 box_add(new_box, WIDGET(state->text), TRUE);
1930
1931 // Make sure we enable fixed num lines when in normal window mode.
1934 }
1937
1938 // Calculate window position.
1940
1941 // Move the window to the correct x,y position.
1943
1944#ifdef ENABLE_XCB
1945 // Display it.
1946 if (config.backend == DISPLAY_XCB) {
1947 xcb_map_window(xcb->connection, CacheState.main_window);
1948 }
1949#endif
1951
1952#ifdef ENABLE_XCB
1953 if (xcb->sncontext != NULL) {
1954 sn_launchee_context_complete(xcb->sncontext);
1955 }
1956#endif
1957
1958 // Exec custom command
1960
1961 // Set it as current window.
1962 rofi_view_set_active(state);
1963 return TRUE;
1964}
1965
1966static int rofi_thread_workers_sort(gconstpointer a, gconstpointer b,
1967 gpointer data G_GNUC_UNUSED) {
1968 thread_state *tsa = (thread_state *)a;
1969 thread_state *tsb = (thread_state *)b;
1970 // lower number is lower priority.. a is sorted above is a > b.
1971 return tsa->priority - tsb->priority;
1972}
1973
1974static void rofi_thread_pool_state_free(gpointer data) {
1975 if (data) {
1976 // This is a weirdness from glib that should not happen.
1977 // It pushes in a 1 to msg sleeping threads to wake up.
1978 // This should be removed from queue to avoid hitting this method.
1979 // In practice, we still hit it (and crash)
1980 if (GPOINTER_TO_UINT(data) == 1) {
1981 // Ignore this entry.
1982 g_debug("Glib thread-pool bug, received pointer with value 1.");
1983 return;
1984 }
1985 thread_state *ts = (thread_state *)data;
1986 if (ts->free) {
1987 ts->free(data);
1988 }
1989 }
1990}
1991
1993 TICK_N("Setup Threadpool, start");
1994 if (config.threads == 0) {
1995 config.threads = 1;
1996 long procs = sysconf(_SC_NPROCESSORS_CONF);
1997 if (procs > 0) {
1998 config.threads = MIN(procs, 128l);
1999 }
2000 }
2001 // Create thread pool
2002 GError *error = NULL;
2003 tpool = g_thread_pool_new_full(rofi_view_call_thread, NULL,
2005 FALSE, &error);
2006 if (error == NULL) {
2007 // Idle threads should stick around for a max of 60 seconds.
2008 g_thread_pool_set_max_idle_time(60000);
2009 // We are allowed to have
2010 g_thread_pool_set_max_threads(tpool, config.threads, &error);
2011 }
2012 // If error occurred during setup of pool, tell user and exit.
2013 if (error != NULL) {
2014 g_warning("Failed to setup thread pool: '%s'", error->message);
2015 g_error_free(error);
2016 exit(EXIT_FAILURE);
2017 }
2018 g_thread_pool_set_sort_function(tpool, rofi_thread_workers_sort, NULL);
2019 TICK_N("Setup Threadpool, done");
2020}
2022 if (tpool) {
2023 // Discard all unprocessed jobs and don't wait for current jobs in execution
2024 g_thread_pool_free(tpool, TRUE, FALSE);
2025 tpool = NULL;
2026 }
2027}
2028Mode *rofi_view_get_mode(RofiViewState *state) { return state->sw; }
2029
2030static gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data) {
2032 if (state) {
2033 widget_disable(WIDGET(state->overlay));
2034 }
2035 CacheState.overlay_timeout = 0;
2037 return G_SOURCE_REMOVE;
2038}
2039
2040void rofi_view_set_overlay_timeout(RofiViewState *state, const char *text) {
2041 if (state->overlay == NULL || state->list_view == NULL) {
2042 return;
2043 }
2044 if (text == NULL) {
2045 widget_disable(WIDGET(state->overlay));
2046 return;
2047 }
2048 rofi_view_set_overlay(state, text);
2049 int timeout = rofi_theme_get_integer(WIDGET(state->overlay), "timeout", 3);
2050 CacheState.overlay_timeout =
2051 g_timeout_add_seconds(timeout, rofi_view_overlay_timeout, state);
2052}
2053
2054void rofi_view_set_overlay(RofiViewState *state, const char *text) {
2055 if (state->overlay == NULL || state->list_view == NULL) {
2056 return;
2057 }
2058 if (CacheState.overlay_timeout > 0) {
2059 g_source_remove(CacheState.overlay_timeout);
2060 CacheState.overlay_timeout = 0;
2061 }
2062 if (text == NULL) {
2063 widget_disable(WIDGET(state->overlay));
2064 return;
2065 }
2066 widget_enable(WIDGET(state->overlay));
2067 textbox_text(state->overlay, text);
2068 // We want to queue a repaint.
2070}
2071
2073 if (state->text) {
2074 textbox_text(state->text, "");
2076 }
2077}
2078
2080 PangoEllipsizeMode mode) {
2081 listview_set_ellipsize(state->list_view, mode);
2082}
2083
2085 state->sw = mode;
2086 // Update prompt;
2087 if (state->prompt) {
2089 }
2090 if (state->sw) {
2091 char *title =
2092 g_strdup_printf("rofi - %s", mode_get_display_name(state->sw));
2094 g_free(title);
2095 } else {
2097 }
2098 if (state->sidebar_bar) {
2099 for (unsigned int j = 0; j < state->num_modes; j++) {
2100 const Mode *tb_mode = rofi_get_mode(j);
2101 textbox_font(state->modes[j],
2102 (tb_mode == state->sw) ? HIGHLIGHT : NORMAL);
2103 }
2104 }
2105 rofi_view_restart(state);
2106 state->reload = TRUE;
2107 state->refilter = TRUE;
2109 rofi_view_update(state, TRUE);
2110}
2111
2113
2114void rofi_view_update(RofiViewState *state, gboolean qr) {
2115 proxy->update(state, qr);
2116}
2117
2120 proxy->temp_configure_notify(state, xce);
2121}
2122
2124 proxy->temp_click_to_exit(state, target);
2125}
2126
2127void rofi_view_frame_callback(void) { proxy->frame_callback(); }
2128
2129void rofi_view_queue_redraw(void) { proxy->queue_redraw(); }
2130
2131void rofi_view_set_window_title(const char *title) {
2132 proxy->set_window_title(title);
2133}
2134
2136 proxy->calculate_window_position(state);
2137}
2138
2140 proxy->calculate_window_width(state);
2141}
2142
2144 return proxy->calculate_window_height(state);
2145}
2146
2148 proxy->window_update_size(state);
2149}
2150
2151void rofi_view_set_cursor(RofiCursorType type) { proxy->set_cursor(type); }
2152
2153void rofi_view_cleanup(void) { proxy->cleanup(); }
2154
2155void rofi_view_hide(void) { proxy->hide(); }
2156
2157void rofi_view_reload(void) { proxy->reload(); }
2158
2159void __create_window(MenuFlags menu_flags) {
2160 proxy->__create_window(menu_flags);
2161}
2162
2163xcb_window_t rofi_view_get_window(void) { return proxy->get_window(); }
2164
2165void rofi_view_get_current_monitor(int *width, int *height) {
2166 proxy->get_current_monitor(width, height);
2167}
2168
2169void rofi_view_set_size(RofiViewState *state, gint width, gint height) {
2170 proxy->set_size(state, width, height);
2171}
2172
2173void rofi_view_get_size(RofiViewState *state, gint *width, gint *height) {
2174 proxy->get_size(state, width, height);
2175}
2176
2177void rofi_view_ping_mouse(RofiViewState *state) { proxy->ping_mouse(state); }
2178
2179void rofi_view_pool_refresh(void) { proxy->pool_refresh(); }
void display_get_clipboard_data(enum clipboard_type type, ClipboardCb callback, void *user_data)
Definition display.c:44
static const display_proxy * proxy
Definition display.c:11
void display_set_input_focus(guint w)
Definition display.c:20
@ CLIPBOARD_DEFAULT
Definition display.h:126
@ CLIPBOARD_PRIMARY
Definition display.h:127
PangoAttrList * helper_token_match_get_pango_attr(RofiHighlightColorStyle th, rofi_int_matcher **tokens, const char *input, PangoAttrList *retv)
Definition helper.c:510
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
Definition helper.c:286
unsigned int levenshtein(const char *needle, const glong needlelen, const char *haystack, const glong haystacklen, int case_sensitive)
Definition helper.c:814
Property * rofi_theme_find_property(ThemeWidget *wid, PropertyType type, const char *property, gboolean exact)
Definition theme.c:745
gboolean helper_execute_command(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context)
Definition helper.c:1072
void helper_select_next_matching_mode(void)
Definition helper.c:83
void helper_tokenize_free(rofi_int_matcher **tokens)
Definition helper.c:146
const char * helper_get_matching_mode_str(void)
Definition helper.c:80
gboolean helper_execute(const char *wd, char **args, const char *error_precmd, const char *error_cmd, RofiHelperExecuteContext *context)
Definition helper.c:1044
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
Definition theme.c:782
int helper_parse_setup(char *string, char ***output, int *length,...)
Definition helper.c:102
#define rofi_fallthrough
Definition helper.h:466
void helper_select_previous_matching_mode(void)
Definition helper.c:89
int parse_case_sensitivity(const char *input)
Definition helper.c:1295
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str, glong slen, int case_sensitive)
Definition helper.c:963
guint key_binding_get_action_from_name(const char *name)
Definition keyb.c:435
BindingsScope
Definition keyb.h:43
KeyBindingAction
Definition keyb.h:58
MouseBindingMouseDefaultAction
Definition keyb.h:174
@ SCOPE_MOUSE_LISTVIEW_ELEMENT
Definition keyb.h:46
@ SCOPE_MOUSE_EDITBOX
Definition keyb.h:49
@ SCOPE_MOUSE_LISTVIEW
Definition keyb.h:45
@ SCOPE_MOUSE_SCROLLBAR
Definition keyb.h:50
@ SCOPE_GLOBAL
Definition keyb.h:44
@ SCOPE_MOUSE_MODE_SWITCHER
Definition keyb.h:51
@ ROW_LAST
Definition keyb.h:111
@ CUSTOM_4
Definition keyb.h:117
@ CUSTOM_17
Definition keyb.h:130
@ CUSTOM_12
Definition keyb.h:125
@ CUSTOM_9
Definition keyb.h:122
@ REMOVE_TO_SOL
Definition keyb.h:90
@ ROW_RIGHT
Definition keyb.h:102
@ ROW_UP
Definition keyb.h:103
@ CUSTOM_8
Definition keyb.h:121
@ ENTRY_HISTORY_DOWN
Definition keyb.h:147
@ SELECT_ELEMENT_9
Definition keyb.h:144
@ MATCHER_DOWN
Definition keyb.h:149
@ MOVE_FRONT
Definition keyb.h:68
@ REMOVE_WORD_FORWARD
Definition keyb.h:82
@ CHANGE_ELLIPSIZE
Definition keyb.h:134
@ ACCEPT_CUSTOM_ALT
Definition keyb.h:95
@ REMOVE_WORD_BACK
Definition keyb.h:80
@ TOGGLE_SORT
Definition keyb.h:135
@ ACCEPT_ENTRY
Definition keyb.h:92
@ ROW_TAB
Definition keyb.h:105
@ PAGE_NEXT
Definition keyb.h:109
@ TOGGLE_CASE_SENSITIVITY
Definition keyb.h:99
@ ELEMENT_NEXT
Definition keyb.h:106
@ MOVE_CHAR_FORWARD
Definition keyb.h:78
@ MOVE_WORD_FORWARD
Definition keyb.h:74
@ MODE_COMPLETE
Definition keyb.h:97
@ CUSTOM_1
Definition keyb.h:114
@ SELECT_ELEMENT_6
Definition keyb.h:141
@ CUSTOM_18
Definition keyb.h:131
@ ENTRY_HISTORY_UP
Definition keyb.h:146
@ CUSTOM_15
Definition keyb.h:128
@ CUSTOM_11
Definition keyb.h:124
@ ACCEPT_CUSTOM
Definition keyb.h:94
@ CUSTOM_5
Definition keyb.h:118
@ CUSTOM_19
Definition keyb.h:132
@ REMOVE_TO_EOL
Definition keyb.h:88
@ SELECT_ELEMENT_3
Definition keyb.h:138
@ ROW_SELECT
Definition keyb.h:112
@ PASTE_PRIMARY
Definition keyb.h:60
@ ROW_DOWN
Definition keyb.h:104
@ CUSTOM_13
Definition keyb.h:126
@ PASTE_SECONDARY
Definition keyb.h:62
@ SELECT_ELEMENT_10
Definition keyb.h:145
@ PAGE_PREV
Definition keyb.h:108
@ CUSTOM_3
Definition keyb.h:116
@ CUSTOM_7
Definition keyb.h:120
@ SELECT_ELEMENT_5
Definition keyb.h:140
@ ROW_FIRST
Definition keyb.h:110
@ CUSTOM_6
Definition keyb.h:119
@ ROW_LEFT
Definition keyb.h:101
@ CUSTOM_14
Definition keyb.h:127
@ SELECT_ELEMENT_4
Definition keyb.h:139
@ MOVE_WORD_BACK
Definition keyb.h:72
@ MOVE_END
Definition keyb.h:70
@ CUSTOM_10
Definition keyb.h:123
@ MODE_NEXT
Definition keyb.h:96
@ COPY_SECONDARY
Definition keyb.h:64
@ REMOVE_CHAR_BACK
Definition keyb.h:86
@ DELETE_ENTRY
Definition keyb.h:100
@ SELECT_ELEMENT_1
Definition keyb.h:136
@ CLEAR_LINE
Definition keyb.h:66
@ MATCHER_UP
Definition keyb.h:148
@ CUSTOM_2
Definition keyb.h:115
@ SELECT_ELEMENT_2
Definition keyb.h:137
@ SCREENSHOT
Definition keyb.h:133
@ CANCEL
Definition keyb.h:113
@ ELEMENT_PREV
Definition keyb.h:107
@ MODE_PREVIOUS
Definition keyb.h:98
@ ACCEPT_ALT
Definition keyb.h:93
@ SELECT_ELEMENT_7
Definition keyb.h:142
@ MOVE_CHAR_BACK
Definition keyb.h:76
@ SELECT_ELEMENT_8
Definition keyb.h:143
@ REMOVE_CHAR_FORWARD
Definition keyb.h:84
@ CUSTOM_16
Definition keyb.h:129
@ MOUSE_CLICK_DOWN
Definition keyb.h:175
@ MOUSE_DCLICK_UP
Definition keyb.h:178
@ MOUSE_CLICK_UP
Definition keyb.h:176
@ MOUSE_DCLICK_DOWN
Definition keyb.h:177
char * mode_preprocess_input(Mode *mode, const char *input)
Definition mode.c:212
cairo_surface_t * mode_get_icon(Mode *mode, unsigned int selected_line, unsigned int height)
Definition mode.c:87
const char * mode_get_display_name(const Mode *mode)
Definition mode.c:189
struct rofi_mode Mode
Definition mode.h:49
unsigned int mode_get_num_entries(const Mode *mode)
Definition mode.c:70
MenuReturn
Definition mode.h:70
char * mode_get_message(const Mode *mode)
Definition mode.c:218
int mode_token_match(const Mode *mode, rofi_int_matcher **tokens, unsigned int selected_line)
Definition mode.c:150
char * mode_get_display_value(const Mode *mode, unsigned int selected_line, int *state, GList **attribute_list, int get_entry)
Definition mode.c:76
char * mode_get_completion(const Mode *mode, unsigned int selected_line)
Definition mode.c:121
@ MENU_CUSTOM_COMMAND
Definition mode.h:84
@ MENU_COMPLETE
Definition mode.h:88
@ MENU_LOWER_MASK
Definition mode.h:92
@ MENU_PREVIOUS
Definition mode.h:86
@ MENU_CANCEL
Definition mode.h:74
@ MENU_QUICK_SWITCH
Definition mode.h:82
@ MENU_ENTRY_DELETE
Definition mode.h:80
@ MENU_NEXT
Definition mode.h:76
@ MENU_CUSTOM_ACTION
Definition mode.h:90
@ MENU_OK
Definition mode.h:72
@ MENU_CUSTOM_INPUT
Definition mode.h:78
const Mode * rofi_get_mode(unsigned int index)
Definition rofi.c:155
void rofi_quit_main_loop(void)
Definition rofi.c:791
#define color_reset
Definition rofi.h:114
unsigned int rofi_get_num_enabled_modes(void)
Definition rofi.c:153
const char * cache_dir
Definition rofi.c:82
#define color_green
Definition rofi.h:120
#define TICK()
Definition timings.h:64
#define TICK_N(a)
Definition timings.h:69
void textbox_font(textbox *tb, TextBoxFontType tbft)
Definition textbox.c:307
TextboxFlags
Definition textbox.h:92
int textbox_keybinding(textbox *tb, KeyBindingAction action)
Definition textbox.c:864
TextBoxFontType
Definition textbox.h:103
void textbox_set_pango_attributes(textbox *tb, PangoAttrList *list)
Definition textbox.c:383
const char * textbox_get_visible_text(const textbox *tb)
Definition textbox.c:371
int textbox_get_cursor(const textbox *tb)
Definition textbox.c:396
void textbox_cursor(textbox *tb, int pos)
Definition textbox.c:636
textbox * textbox_create(widget *parent, WidgetType type, const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text, double xalign, double yalign)
Definition textbox.c:203
void textbox_cursor_end(textbox *tb)
Definition textbox.c:738
gboolean textbox_append_text(textbox *tb, const char *pad, const int pad_len)
Definition textbox.c:926
PangoAttrList * textbox_get_pango_attributes(textbox *tb)
Definition textbox.c:377
void textbox_text(textbox *tb, const char *text)
Definition textbox.c:403
char * textbox_get_text(const textbox *tb)
Definition textbox.c:390
@ TB_AUTOHEIGHT
Definition textbox.h:93
@ TB_PASSWORD
Definition textbox.h:98
@ TB_MARKUP
Definition textbox.h:96
@ TB_WRAP
Definition textbox.h:97
@ TB_EDITABLE
Definition textbox.h:95
@ TB_AUTOWIDTH
Definition textbox.h:94
@ URGENT
Definition textbox.h:107
@ HIGHLIGHT
Definition textbox.h:118
@ NORMAL
Definition textbox.h:105
void rofi_view_cleanup(void)
Definition view.c:2153
void rofi_view_set_overlay(RofiViewState *state, const char *text)
Definition view.c:2054
void __create_window(MenuFlags menu_flags)
Definition view.c:2159
void rofi_view_clear_input(RofiViewState *state)
Definition view.c:2072
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Definition view.c:2084
Mode * rofi_view_get_mode(RofiViewState *state)
Definition view.c:2028
void rofi_view_hide(void)
Definition view.c:2155
void rofi_view_calculate_window_position(RofiViewState *state)
Definition view.c:2135
void rofi_view_reload(void)
Definition view.c:2157
xcb_window_t rofi_view_get_window(void)
Definition view.c:2163
void rofi_view_remove_active(RofiViewState *state)
Definition view.c:301
void rofi_view_set_overlay_timeout(RofiViewState *state, const char *text)
Definition view.c:2040
int rofi_view_error_dialog(const char *msg, int markup)
Definition view.c:1915
void rofi_view_set_active(RofiViewState *state)
Definition view.c:308
void rofi_view_queue_redraw(void)
Definition view.c:2129
RofiViewState * rofi_view_get_active(void)
Definition view.c:299
void rofi_view_restart(RofiViewState *state)
Definition view.c:294
MenuFlags
Definition view.h:54
void rofi_view_handle_text(RofiViewState *state, char *text)
Definition view.c:1401
void rofi_view_trigger_action(RofiViewState *state, BindingsScope scope, guint action)
Definition view.c:1360
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition view.c:371
unsigned int rofi_view_get_completed(const RofiViewState *state)
Definition view.c:388
gboolean rofi_view_check_action(RofiViewState *state, BindingsScope scope, guint action)
Definition view.c:1329
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition view.c:392
void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y, gboolean find_mouse_target)
Definition view.c:1435
void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target)
Definition view.c:2123
void rofi_view_finalize(RofiViewState *state)
Definition view.c:944
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition view.c:330
void rofi_view_temp_configure_notify(RofiViewState *state, xcb_configure_notify_event_t *xce)
Definition view.c:2118
void rofi_view_frame_callback(void)
Definition view.c:2127
void rofi_view_free(RofiViewState *state)
Definition view.c:353
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition view.c:1795
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
Definition view.c:375
unsigned int rofi_view_get_next_position(const RofiViewState *state)
Definition view.c:379
void rofi_view_maybe_update(RofiViewState *state)
Definition view.c:1495
@ MENU_PASSWORD
Definition view.h:58
@ MENU_NORMAL_WINDOW
Definition view.h:60
@ MENU_ERROR_DIALOG
Definition view.h:62
@ MENU_NORMAL
Definition view.h:56
void rofi_view_ping_mouse(RofiViewState *state)
Definition view.c:2177
void rofi_capture_screenshot(void)
Definition view.c:132
void rofi_view_workers_initialize(void)
Definition view.c:1992
WidgetTriggerActionResult textbox_button_trigger_action(widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data)
Definition view.c:1519
void rofi_view_set_size(RofiViewState *state, gint width, gint height)
Definition view.c:2169
void rofi_view_set_window_title(const char *title)
Definition view.c:2131
void input_history_save(void)
Definition view.c:526
void input_history_initialize(void)
Definition view.c:483
void rofi_view_ellipsize_listview(RofiViewState *state, PangoEllipsizeMode mode)
Definition view.c:2079
void rofi_view_set_cursor(RofiCursorType type)
Definition view.c:2151
void rofi_view_get_current_monitor(int *width, int *height)
Definition view.c:2165
void rofi_view_workers_finalize(void)
Definition view.c:2021
void rofi_view_pool_refresh(void)
Definition view.c:2179
void rofi_view_get_size(RofiViewState *state, gint *width, gint *height)
Definition view.c:2173
void box_add(box *wid, widget *child, gboolean expand)
Definition box.c:287
box * box_create(widget *parent, const char *name, RofiOrientation type)
Definition box.c:347
struct _box box
Definition box.h:49
void container_add(container *cont, widget *child)
Definition container.c:68
container * container_create(widget *parent, const char *name)
Definition container.c:103
void icon_set_surface(icon *icon_widget, cairo_surface_t *surf)
Definition icon.c:139
icon * icon_create(widget *parent, const char *name)
Definition icon.c:152
struct _icon icon
Definition icon.h:44
void listview_nav_page_next(listview *lv)
Definition listview.c:1087
void listview_set_fixed_num_lines(listview *lv)
Definition listview.c:1166
struct _listview listview
Definition listview.h:45
listview * listview_create(widget *parent, const char *name, listview_update_callback cb, listview_page_changed_cb page_cb, void *udata, unsigned int eh, gboolean reverse)
Definition listview.c:784
void listview_set_num_elements(listview *lv, unsigned int rows)
Definition listview.c:622
void listview_nav_right(listview *lv)
Definition listview.c:985
void listview_set_mouse_activated_cb(listview *lv, listview_mouse_activated_cb cb, void *udata)
Definition listview.c:1145
void listview_toggle_ellipsizing(listview *lv)
Definition listview.c:1181
void listview_set_ellipsize(listview *lv, PangoEllipsizeMode mode)
Definition listview.c:1172
void listview_set_selected(listview *lv, unsigned int selected)
Definition listview.c:646
void listview_set_max_lines(listview *lv, unsigned int max_lines)
Definition listview.c:1154
void listview_nav_left(listview *lv)
Definition listview.c:962
void listview_set_scroll_type(listview *lv, ScrollType type)
Definition listview.c:1139
void listview_nav_prev(listview *lv)
Definition listview.c:899
unsigned int listview_get_selected(listview *lv)
Definition listview.c:639
void listview_set_filtered(listview *lv, gboolean filtered)
Definition listview.c:1198
void listview_nav_up(listview *lv)
Definition listview.c:925
void listview_nav_next(listview *lv)
Definition listview.c:893
void listview_nav_page_prev(listview *lv)
Definition listview.c:1077
void listview_set_selection_changed_callback(listview *lv, listview_selection_changed_callback cb, void *udata)
Definition listview.c:1204
void listview_nav_down(listview *lv)
Definition listview.c:943
WidgetTriggerActionResult widget_trigger_action(widget *wid, guint action, gint x, gint y)
Definition widget.c:546
void widget_queue_redraw(widget *wid)
Definition widget.c:487
static void widget_enable(widget *wid)
Definition widget.h:176
void widget_free(widget *wid)
Definition widget.c:425
void widget_draw(widget *wid, cairo_t *d)
Definition widget.c:140
struct _widget widget
Definition widget.h:49
WidgetType
Definition widget.h:54
#define WIDGET(a)
Definition widget.h:117
static void widget_disable(widget *wid)
Definition widget.h:168
WidgetTriggerActionResult
Definition widget.h:74
WidgetTriggerActionResult widget_check_action(widget *wid, G_GNUC_UNUSED guint action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y)
Definition widget.c:529
void widget_set_trigger_action_handler(widget *wid, widget_trigger_action_cb cb, void *cb_data)
Definition widget.c:557
int widget_get_desired_height(widget *wid, const int width)
Definition widget.c:644
gboolean widget_motion_notify(widget *wid, gint x, gint y)
Definition widget.c:566
void widget_xy_to_relative(widget *wid, gint *x, gint *y)
Definition widget.c:468
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition widget.c:510
@ WIDGET_TYPE_UNKNOWN
Definition widget.h:56
@ WIDGET_TYPE_LISTVIEW_ELEMENT
Definition widget.h:60
@ WIDGET_TYPE_TEXTBOX_TEXT
Definition widget.h:68
@ WIDGET_TYPE_MODE_SWITCHER
Definition widget.h:66
@ WIDGET_TYPE_EDITBOX
Definition widget.h:62
@ WIDGET_TRIGGER_ACTION_RESULT_HANDLED
Definition widget.h:78
@ WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END
Definition widget.h:82
@ WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN
Definition widget.h:80
@ WIDGET_TRIGGER_ACTION_RESULT_IGNORED
Definition widget.h:76
@ P_INTEGER
Definition rofi-types.h:12
@ P_DOUBLE
Definition rofi-types.h:14
@ P_STRING
Definition rofi-types.h:16
@ ROFI_ORIENTATION_HORIZONTAL
Definition rofi-types.h:141
@ ROFI_ORIENTATION_VERTICAL
Definition rofi-types.h:140
RofiCursorType
Definition rofi-types.h:147
@ ROFI_CURSOR_POINTER
Definition rofi-types.h:149
@ ROFI_CURSOR_TEXT
Definition rofi-types.h:150
@ ROFI_CURSOR_DEFAULT
Definition rofi-types.h:148
struct _thread_state thread_state
@ ROFI_HL_UNDERLINE
Definition rofi-types.h:56
@ ROFI_HL_BOLD
Definition rofi-types.h:54
GList * list_of_warning_msgs
Definition rofi.c:90
void process_result(RofiViewState *state)
Definition rofi.c:238
Settings config
@ DISPLAY_WAYLAND
Definition settings.h:54
@ DISPLAY_XCB
Definition settings.h:53
@ SORT_FZF
Definition settings.h:50
@ SORT_NORMAL
Definition settings.h:50
PropertyValue value
Definition rofi-types.h:293
PropertyType type
Definition rofi-types.h:291
unsigned int filtered_lines
container * mesg_box
textbox * text
widget * motion_target
textbox * mesg_tb
textbox * overlay
icon * icon_current_entry
gboolean case_sensitive
textbox ** modes
struct RofiViewState::@205064276262334135157147273370175004036316141305 mouse
listview * list_view
unsigned int num_lines
unsigned int previous_line
unsigned int num_modes
MenuReturn retv
void(* finalize)(struct RofiViewState *state)
textbox * prompt
unsigned int * line_map
textbox * tb_filtered_rows
rofi_int_matcher ** tokens
textbox * tb_current_entry
textbox * tb_total_rows
unsigned int selected_line
KeyBindingAction prev_action
textbox * case_indicator
MenuFlags menu_flags
const char * pattern
Definition view.c:432
unsigned int count
Definition view.c:429
GMutex * mutex
Definition view.c:418
unsigned int stop
Definition view.c:427
thread_state st
Definition view.c:413
RofiViewState * state
Definition view.c:423
unsigned int * acount
Definition view.c:420
unsigned int start
Definition view.c:425
GCond * cond
Definition view.c:416
void(* callback)(struct _thread_state *t, gpointer data)
Definition rofi-types.h:368
void(* free)(void *)
Definition rofi-types.h:369
RofiCursorType cursor_type
char * text
Definition textbox.h:64
int rofi_theme_get_integer(const widget *wid, const char *property, int def)
Definition theme.c:842
RofiHighlightColorStyle rofi_theme_get_highlight(widget *wid, const char *property, RofiHighlightColorStyle th)
Definition theme.c:1310
GList * rofi_theme_get_list_strings(const widget *wid, const char *property)
Definition theme.c:1260
const char * rofi_theme_get_string(const widget *wid, const char *property, const char *def)
Definition theme.c:989
struct _view_proxy view_proxy
static void rofi_view_call_thread(gpointer data, gpointer user_data)
Definition view.c:442
static void rofi_view_nav_last(RofiViewState *state)
Definition view.c:630
void view_init(const view_proxy *view_in)
Definition view.c:67
static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data)
Definition view.c:267
void rofi_view_refilter(RofiViewState *state)
Definition view.c:899
static void rofi_error_user_callback(const char *msg)
Definition view.c:1903
static char * get_matching_state(RofiViewState *state)
Definition view.c:91
struct _thread_state_view thread_state_view
static void rofi_view_nav_row_select(RofiViewState *state)
Definition view.c:600
static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom, void *udata)
Definition view.c:1577
static gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data)
Definition view.c:2030
static void screenshot_taken_user_callback(const char *path)
Definition view.c:117
static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget, const char *name)
Definition view.c:1590
static void update_callback(textbox *t, icon *ico, unsigned int index, void *udata, TextBoxFontType *type, gboolean full)
Definition view.c:687
static void rofi_view_nav_row_tab(RofiViewState *state)
Definition view.c:576
void rofi_view_window_update_size(RofiViewState *state)
Definition view.c:2147
static void rofi_view_reload_message_bar(RofiViewState *state)
Definition view.c:208
static void rofi_view_nav_first(RofiViewState *state)
Definition view.c:620
static gboolean rofi_view_refilter_real(RofiViewState *state)
Definition view.c:757
static void page_changed_callback(void)
Definition view.c:742
void rofi_view_update(RofiViewState *state, gboolean qr)
Definition view.c:2114
static RofiViewState * __rofi_view_state_create(void)
Definition view.c:404
static void rofi_view_trigger_global_action(KeyBindingAction action)
Definition view.c:982
static void rofi_view_input_changed(void)
Definition view.c:954
void rofi_view_calculate_window_width(struct RofiViewState *state)
Definition view.c:2139
static void filter_elements(thread_state *ts, G_GNUC_UNUSED gpointer user_data)
Definition view.c:447
void process_result(RofiViewState *state)
Definition rofi.c:238
static void rofi_view_update_prompt(RofiViewState *state)
Definition view.c:200
static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data)
Definition view.c:261
GThreadPool * tpool
Definition view.c:70
RofiViewState * current_active_menu
Definition view.c:73
static void rofi_thread_pool_state_free(gpointer data)
Definition view.c:1974
static int rofi_thread_workers_sort(gconstpointer a, gconstpointer b, gpointer data G_GNUC_UNUSED)
Definition view.c:1966
int rofi_view_calculate_window_height(RofiViewState *state)
Definition view.c:2143
static void selection_changed_user_callback(unsigned int index, RofiViewState *state)
Definition view.c:638
static void rofi_view_take_action(const char *name)
Definition view.c:245
static void selection_changed_callback(G_GNUC_UNUSED listview *lv, unsigned int index, void *udata)
Definition view.c:654
static void rofi_quit_user_callback(RofiViewState *state)
Definition view.c:1463
struct _rofi_view_cache_state CacheState
Definition view.c:75
static RofiCursorType rofi_view_resolve_cursor(RofiViewState *state, gint x, gint y)
Definition view.c:1427
static int lev_sort(const void *p1, const void *p2, void *arg)
Definition view.c:109
static WidgetTriggerActionResult textbox_sidebar_modes_trigger_action(widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data)
Definition view.c:1548
static void _rofi_view_reload_row(RofiViewState *state)
Definition view.c:747
static void rofi_view_refilter_force(RofiViewState *state)
Definition view.c:929
unsigned long long count
Definition view.c:76
int xcb_window_t
Definition xcb-dummy.h:9
#define XCB_WINDOW_NONE
Definition xcb-dummy.h:12
int xcb_configure_notify_event_t
Definition xcb-dummy.h:8
xcb_stuff * xcb
Definition display.c:103
void xcb_stuff_set_clipboard(char *data)
Definition display.c:1989
xcb_atom_t netatoms[NUM_NETATOMS]
Definition display.c:115
X11CursorType cursor_type
Definition view.c:127
static X11CursorType rofi_cursor_type_to_x11_cursor_type(RofiCursorType type)
Definition view.c:396
X11CursorType
Definition xcb.h:140
@ CURSOR_POINTER
Definition xcb.h:144
@ CURSOR_DEFAULT
Definition xcb.h:142
@ CURSOR_TEXT
Definition xcb.h:146