rofi 1.7.9
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#ifdef XCB_IMDKIT
41#include <xcb-imdkit/encoding.h>
42#endif
43#include <xcb/xcb_ewmh.h>
44#include <xcb/xcb_icccm.h>
45#include <xcb/xkb.h>
46#include <xkbcommon/xkbcommon-x11.h>
47
48#include <cairo-xcb.h>
49#include <cairo.h>
50#include <gio/gio.h>
51
53#define SN_API_NOT_YET_FROZEN
54#include "rofi.h"
55#include <libsn/sn.h>
56
57#include "settings.h"
58#include "timings.h"
59
60#include "display.h"
61#include "helper-theme.h"
62#include "helper.h"
63#include "mode.h"
64#include "modes/modes.h"
65#include "xcb-internal.h"
66
67#include "view-internal.h"
68#include "view.h"
69
70#include "theme.h"
71
72#include "xcb.h"
73
80void rofi_view_update(RofiViewState *state, gboolean qr);
81
83
84#ifdef XCB_IMDKIT
85static void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,
86 G_GNUC_UNUSED uint32_t flag, char *str,
87 uint32_t length, G_GNUC_UNUSED uint32_t *keysym,
88 G_GNUC_UNUSED size_t nKeySym,
89 G_GNUC_UNUSED void *user_data);
90static void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,
91 G_GNUC_UNUSED void *user_data);
92xcb_xim_im_callback xim_callback = {.forward_event =
93 x11_event_handler_fowarding,
94 .commit_string = xim_commit_string,
95 .disconnected = xim_disconnected};
96#endif
97
99GThreadPool *tpool = NULL;
100
103
104typedef struct {
105 char *string;
106 int index;
108
111struct {
113 xcb_window_t main_window;
115 cairo_surface_t *fake_bg;
117 xcb_gcontext_t gc;
119 xcb_pixmap_t edit_pixmap;
121 cairo_surface_t *edit_surf;
123 cairo_t *edit_draw;
129 GQueue views;
138
143 gboolean delayed_mode;
149 unsigned long long count;
153 gboolean fullscreen;
164} CacheState = {.main_window = XCB_WINDOW_NONE,
165 .fake_bg = NULL,
166 .edit_surf = NULL,
167 .edit_draw = NULL,
168 .fake_bgrel = FALSE,
169 .flags = MENU_NORMAL,
170 .views = G_QUEUE_INIT,
171 .idle_timeout = 0,
172 .refilter_timeout = 0,
173 .refilter_timeout_count = 0,
174 .max_refilter_time = 0.0,
175 .delayed_mode = FALSE,
176 .user_timeout = 0,
177 .overlay_timeout = 0,
178 .count = 0L,
179 .repaint_source = 0,
180 .fullscreen = FALSE,
181 .entry_history_enable = TRUE,
182 .entry_history = NULL,
183 .entry_history_length = 0,
184 .entry_history_index = 0};
185
186void rofi_view_get_current_monitor(int *width, int *height) {
187 if (width) {
188 *width = CacheState.mon.w;
189 }
190 if (height) {
191 *height = CacheState.mon.h;
192 }
193}
194static char *get_matching_state(RofiViewState *state) {
195 if (state->case_sensitive) {
196 if (config.sort) {
197 return "±";
198 }
199 return "-";
200 }
201 if (config.sort) {
202 return "+";
203 }
204 return " ";
205}
206
210static int lev_sort(const void *p1, const void *p2, void *arg) {
211 const int *a = p1;
212 const int *b = p2;
213 int *distances = arg;
214
215 return distances[*a] - distances[*b];
216}
217
218static void screenshot_taken_user_callback(const char *path) {
219 if (config.on_screenshot_taken == NULL)
220 return;
221
222 char **args = NULL;
223 int argv = 0;
224 helper_parse_setup(config.on_screenshot_taken, &args, &argv, "{path}", path,
225 (char *)0);
226 if (args != NULL)
227 helper_execute(NULL, args, "", config.on_screenshot_taken, NULL);
228}
229
235 if (state == NULL || state->main_window == NULL) {
236 g_warning("Nothing to screenshot.");
237 return;
238 }
239 const char *outp = g_getenv("ROFI_PNG_OUTPUT");
240 const char *xdg_pict_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
241 if (outp == NULL && xdg_pict_dir == NULL) {
242 g_warning("XDG user picture directory or ROFI_PNG_OUTPUT is not set. "
243 "Cannot store screenshot.");
244 return;
245 }
246 // Get current time.
247 GDateTime *now = g_date_time_new_now_local();
248 // Format filename.
249 char *timestmp = g_date_time_format(now, "rofi-%Y-%m-%d-%H%M");
250 char *filename = g_strdup_printf("%s-%05d.png", timestmp, 0);
251 // Build full path
252 char *fpath = NULL;
253 if (outp == NULL) {
254 int index = 0;
255 fpath = g_build_filename(xdg_pict_dir, filename, NULL);
256 while (g_file_test(fpath, G_FILE_TEST_EXISTS) && index < 99999) {
257 g_free(fpath);
258 g_free(filename);
259 // Try the next index.
260 index++;
261 // Format filename.
262 filename = g_strdup_printf("%s-%05d.png", timestmp, index);
263 // Build full path
264 fpath = g_build_filename(xdg_pict_dir, filename, NULL);
265 }
266 } else {
267 fpath = g_strdup(outp);
268 }
269 fprintf(stderr, color_green "Storing screenshot %s\n" color_reset, fpath);
270 cairo_surface_t *surf = cairo_image_surface_create(
271 CAIRO_FORMAT_ARGB32, state->width, state->height);
272 cairo_status_t status = cairo_surface_status(surf);
273 if (status != CAIRO_STATUS_SUCCESS) {
274 g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
275 cairo_status_to_string(status));
276 } else {
277 cairo_t *draw = cairo_create(surf);
278 status = cairo_status(draw);
279 if (status != CAIRO_STATUS_SUCCESS) {
280 g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
281 cairo_status_to_string(status));
282 } else {
283 widget_draw(WIDGET(state->main_window), draw);
284 status = cairo_surface_write_to_png(surf, fpath);
285 if (status != CAIRO_STATUS_SUCCESS) {
286 g_warning("Failed to produce screenshot '%s', got error: '%s'", fpath,
287 cairo_status_to_string(status));
288 }
290 }
291 cairo_destroy(draw);
292 }
293 // Cleanup
294 cairo_surface_destroy(surf);
295 g_free(fpath);
296 g_free(filename);
297 g_free(timestmp);
298 g_date_time_unref(now);
299}
300
304static struct {
306 GTimer *time;
308 uint64_t draws;
310 double last_ts;
312 double min;
313} BenchMark = {.time = NULL, .draws = 0, .last_ts = 0.0, .min = G_MAXDOUBLE};
314
315static gboolean bench_update(void) {
316 if (!config.benchmark_ui) {
317 return FALSE;
318 }
319 BenchMark.draws++;
320 if (BenchMark.time == NULL) {
321 BenchMark.time = g_timer_new();
322 }
323
324 if ((BenchMark.draws & 1023) == 0) {
325 double ts = g_timer_elapsed(BenchMark.time, NULL);
326 double fps = 1024 / (ts - BenchMark.last_ts);
327
328 if (fps < BenchMark.min) {
329 BenchMark.min = fps;
330 }
331 printf("current: %.2f fps, avg: %.2f fps, min: %.2f fps, %lu draws\r\n",
332 fps, BenchMark.draws / ts, BenchMark.min, BenchMark.draws);
333
334 BenchMark.last_ts = ts;
335 }
336 return TRUE;
337}
338
339static gboolean rofi_view_repaint(G_GNUC_UNUSED void *data) {
341 // Repaint the view (if needed).
342 // After a resize the edit_pixmap surface might not contain anything
343 // anymore. If we already re-painted, this does nothing.
344
345 TICK_N("Update start");
347 g_debug("expose event");
348 TICK_N("Expose");
349 xcb_copy_area(xcb->connection, CacheState.edit_pixmap,
350 CacheState.main_window, CacheState.gc, 0, 0, 0, 0,
352 xcb_flush(xcb->connection);
353 TICK_N("flush");
354 CacheState.repaint_source = 0;
355 }
356 return (bench_update() == TRUE) ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
357}
358
360 if (state->prompt) {
361 const char *str = mode_get_display_name(state->sw);
362 textbox_text(state->prompt, str);
363 }
364}
365
383 int location = rofi_theme_get_position(WIDGET(state->main_window), "location",
384 loc_transtable[config.location]);
385 int anchor =
386 rofi_theme_get_position(WIDGET(state->main_window), "anchor", location);
387
388 if (CacheState.fullscreen) {
389 state->x = CacheState.mon.x;
390 state->y = CacheState.mon.y;
391 return;
392 }
393 state->y = CacheState.mon.y + (CacheState.mon.h) / 2;
394 state->x = CacheState.mon.x + (CacheState.mon.w) / 2;
395 // Determine window location
396 switch (location) {
397 case WL_NORTH_WEST:
398 state->x = CacheState.mon.x;
400 case WL_NORTH:
401 state->y = CacheState.mon.y;
402 break;
403 case WL_NORTH_EAST:
404 state->y = CacheState.mon.y;
406 case WL_EAST:
407 state->x = CacheState.mon.x + CacheState.mon.w;
408 break;
409 case WL_SOUTH_EAST:
410 state->x = CacheState.mon.x + CacheState.mon.w;
412 case WL_SOUTH:
413 state->y = CacheState.mon.y + CacheState.mon.h;
414 break;
415 case WL_SOUTH_WEST:
416 state->y = CacheState.mon.y + CacheState.mon.h;
418 case WL_WEST:
419 state->x = CacheState.mon.x;
420 break;
421 case WL_CENTER:;
423 default:
424 break;
425 }
426 switch (anchor) {
427 case WL_SOUTH_WEST:
428 state->y -= state->height;
429 break;
430 case WL_SOUTH:
431 state->x -= state->width / 2;
432 state->y -= state->height;
433 break;
434 case WL_SOUTH_EAST:
435 state->x -= state->width;
436 state->y -= state->height;
437 break;
438 case WL_NORTH_EAST:
439 state->x -= state->width;
440 break;
441 case WL_NORTH_WEST:
442 break;
443 case WL_NORTH:
444 state->x -= state->width / 2;
445 break;
446 case WL_EAST:
447 state->x -= state->width;
448 state->y -= state->height / 2;
449 break;
450 case WL_WEST:
451 state->y -= state->height / 2;
452 break;
453 case WL_CENTER:
454 state->y -= state->height / 2;
455 state->x -= state->width / 2;
456 break;
457 default:
458 break;
459 }
460 // Apply offset.
462 "x-offset", config.x_offset);
464 "y-offset", config.y_offset);
467}
468
470 if (state == NULL) {
471 return;
472 }
473 uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
474 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
475 uint32_t vals[] = {state->x, state->y, state->width, state->height};
476
477 // Display it.
478 xcb_configure_window(xcb->connection, CacheState.main_window, mask, vals);
479 cairo_destroy(CacheState.edit_draw);
480 cairo_surface_destroy(CacheState.edit_surf);
481
482 xcb_free_pixmap(xcb->connection, CacheState.edit_pixmap);
483 CacheState.edit_pixmap = xcb_generate_id(xcb->connection);
484 xcb_create_pixmap(xcb->connection, depth->depth, CacheState.edit_pixmap,
485 CacheState.main_window, state->width, state->height);
486
487 CacheState.edit_surf =
488 cairo_xcb_surface_create(xcb->connection, CacheState.edit_pixmap, visual,
489 state->width, state->height);
490 CacheState.edit_draw = cairo_create(CacheState.edit_surf);
491
492 g_debug("Re-size window based internal request: %dx%d.", state->width,
493 state->height);
494 // Should wrap main window in a widget.
495 widget_resize(WIDGET(state->main_window), state->width, state->height);
496}
497
498extern GList *list_of_warning_msgs;
500 if (state->mesg_box == NULL) {
501 return;
502 }
503 char *msg = mode_get_message(state->sw);
504 if (msg || list_of_warning_msgs) {
506
507 GString *emesg = g_string_new(msg);
509 if (msg) {
510 g_string_append_c(emesg, '\n');
511 }
512 g_string_append(
513 emesg, "The following warnings were detected when starting rofi:\n");
514 GList *iter = g_list_first(list_of_warning_msgs);
515 int index = 0;
516 for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
517 GString *in_msg = (GString *)(iter->data);
518 g_string_append(emesg, "\n\n");
519 g_string_append(emesg, in_msg->str);
520 index++;
521 }
522 if (g_list_length(iter) > 1) {
523 g_string_append_printf(emesg, "\nThere are <b>%u</b> more errors.",
524 g_list_length(iter) - 1);
525 }
526 }
527 textbox_text(state->mesg_tb, emesg->str);
529 g_string_free(emesg, TRUE);
530 g_free(msg);
531 } else {
533 }
534}
535
536static gboolean rofi_view_reload_idle(G_GNUC_UNUSED gpointer data) {
538 // For UI update on this.
539 if (current_active_menu->tb_total_rows) {
540 char *r =
541 g_strdup_printf("%u", mode_get_num_entries(current_active_menu->sw));
542 textbox_text(current_active_menu->tb_total_rows, r);
543 g_free(r);
544 }
545 current_active_menu->reload = TRUE;
546 current_active_menu->refilter = TRUE;
548 }
549 CacheState.idle_timeout = 0;
550 return G_SOURCE_REMOVE;
551}
552
553static void rofi_view_take_action(const char *name) {
554 ThemeWidget *wid = rofi_config_find_widget(name, NULL, TRUE);
555 if (wid) {
557 Property *p = rofi_theme_find_property(wid, P_STRING, "action", TRUE);
558 if (p != NULL && p->type == P_STRING) {
559 const char *action = p->value.s;
560 guint id = key_binding_get_action_from_name(action);
561 if (id != UINT32_MAX) {
563 } else {
564 g_warning("Failed to parse keybinding: %s\r\n", action);
565 }
566 }
567 }
568}
569static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data) {
570 CacheState.user_timeout = 0;
571 rofi_view_take_action("timeout");
572 return G_SOURCE_REMOVE;
573}
574
575static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data) {
576 if (CacheState.user_timeout > 0) {
577 g_source_remove(CacheState.user_timeout);
578 CacheState.user_timeout = 0;
579 }
580 {
582 ThemeWidget *wid = rofi_config_find_widget("timeout", NULL, TRUE);
583 if (wid) {
585 Property *p = rofi_theme_find_property(wid, P_INTEGER, "delay", TRUE);
586 if (p != NULL && p->type == P_INTEGER && p->value.i > 0) {
587 int delay = p->value.i;
588 CacheState.user_timeout =
589 g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);
590 } else {
591 Property *prop = rofi_theme_find_property(wid, P_DOUBLE, "delay", TRUE);
592 if (prop != NULL && prop->type == P_DOUBLE && prop->value.f > 0.01) {
593 double delay = prop->value.f;
594 CacheState.user_timeout =
595 g_timeout_add(delay * 1000, rofi_view_user_timeout, NULL);
596 }
597 }
598 }
599 }
600}
601
603 // @TODO add check if current view is equal to the callee
604 if (CacheState.idle_timeout == 0) {
605 CacheState.idle_timeout =
606 g_timeout_add(1000 / 100, rofi_view_reload_idle, NULL);
607 }
608}
610 if (current_active_menu && CacheState.repaint_source == 0) {
611 CacheState.count++;
612 g_debug("redraw %llu", CacheState.count);
613 CacheState.repaint_source =
614 g_idle_add_full(G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL);
615 }
616}
617
619 state->quit = FALSE;
620 state->retv = MENU_CANCEL;
621}
622
624
626 if (state == current_active_menu) {
628 } else if (state) {
629 g_queue_remove(&(CacheState.views), state);
630 }
631}
633 if (current_active_menu != NULL && state != NULL) {
634 g_queue_push_head(&(CacheState.views), current_active_menu);
635 // TODO check.
636 current_active_menu = state;
637 g_debug("stack view.");
640 return;
641 }
642 if (state == NULL && !g_queue_is_empty(&(CacheState.views))) {
643 g_debug("pop view.");
644 current_active_menu = g_queue_pop_head(&(CacheState.views));
647 return;
648 }
649 g_assert((current_active_menu == NULL && state != NULL) ||
650 (current_active_menu != NULL && state == NULL));
651 current_active_menu = state;
653}
654
656 unsigned int selected_line) {
657 state->selected_line = selected_line;
658 // Find the line.
659 unsigned int selected = 0;
660 for (unsigned int i = 0; ((state->selected_line)) < UINT32_MAX && !selected &&
661 i < state->filtered_lines;
662 i++) {
663 if (state->line_map[i] == (state->selected_line)) {
664 selected = i;
665 break;
666 }
667 }
668 listview_set_selected(state->list_view, selected);
669 // Clear the window and force an expose event resulting in a redraw.
670 xcb_clear_area(xcb->connection, 1, CacheState.main_window, 0, 0, 1, 1);
671 xcb_flush(xcb->connection);
672}
673
675 if (state->tokens) {
677 state->tokens = NULL;
678 }
679 // Do this here?
680 // Wait for final release?
682
683 g_free(state->line_map);
684 g_free(state->distance);
685 // Free the switcher boxes.
686 // When state is free'ed we should no longer need these.
687 g_free(state->modes);
688 state->num_modes = 0;
689 g_free(state);
690}
691
693 return state->retv;
694}
695
696unsigned int rofi_view_get_selected_line(const RofiViewState *state) {
697 return state->selected_line;
698}
699
700unsigned int rofi_view_get_next_position(const RofiViewState *state) {
701 unsigned int next_pos = state->selected_line;
702 unsigned int selected = listview_get_selected(state->list_view);
703 if ((selected + 1) < state->num_lines) {
704 (next_pos) = state->line_map[selected + 1];
705 }
706 return next_pos;
707}
708
709unsigned int rofi_view_get_completed(const RofiViewState *state) {
710 return state->quit;
711}
712
713const char *rofi_view_get_user_input(const RofiViewState *state) {
714 if (state->text) {
715 return state->text->text;
716 }
717 return NULL;
718}
719
726 return g_malloc0(sizeof(RofiViewState));
727}
728
732typedef struct _thread_state_view {
735
737 GCond *cond;
739 GMutex *mutex;
741 unsigned int *acount;
742
746 unsigned int start;
748 unsigned int stop;
750 unsigned int count;
751
753 const char *pattern;
755 glong plen;
763static void rofi_view_call_thread(gpointer data, gpointer user_data) {
764 thread_state *t = (thread_state *)data;
765 t->callback(t, user_data);
766}
767
769 G_GNUC_UNUSED gpointer user_data) {
771 for (unsigned int i = t->start; i < t->stop; i++) {
772 int match = mode_token_match(t->state->sw, t->state->tokens, i);
773 // If each token was matched, add it to list.
774 if (match) {
775 t->state->line_map[t->start + t->count] = i;
776 if (config.sort) {
777 // This is inefficient, need to fix it.
778 char *str = mode_get_completion(t->state->sw, i);
779 glong slen = g_utf8_strlen(str, -1);
780 switch (config.sorting_method_enum) {
781 case SORT_FZF:
783 t->pattern, t->plen, str, slen, t->state->case_sensitive);
784 break;
785 case SORT_NORMAL:
786 default:
787 t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen,
789 break;
790 }
791 g_free(str);
792 }
793 t->count++;
794 }
795 }
796 if (t->acount != NULL) {
797 g_mutex_lock(t->mutex);
798 (*(t->acount))--;
799 g_cond_signal(t->cond);
800 g_mutex_unlock(t->mutex);
801 }
802}
803
804static void
806 const char *const fake_background) {
807 if (CacheState.fake_bg == NULL) {
808 cairo_surface_t *s = NULL;
813 TICK_N("Fake start");
814 if (g_strcmp0(fake_background, "real") == 0) {
815 return;
816 }
817 if (g_strcmp0(fake_background, "screenshot") == 0) {
819 } else if (g_strcmp0(fake_background, "background") == 0) {
821 } else {
822 char *fpath = rofi_expand_path(fake_background);
823 g_debug("Opening %s to use as background.", fpath);
824 s = cairo_image_surface_create_from_png(fpath);
825 CacheState.fake_bgrel = TRUE;
826 g_free(fpath);
827 }
828 TICK_N("Get surface.");
829 if (s != NULL) {
830 if (cairo_surface_status(s) != CAIRO_STATUS_SUCCESS) {
831 g_debug("Failed to open surface fake background: %s",
832 cairo_status_to_string(cairo_surface_status(s)));
833 cairo_surface_destroy(s);
834 s = NULL;
835 } else {
836 CacheState.fake_bg = cairo_image_surface_create(
837 CAIRO_FORMAT_ARGB32, CacheState.mon.w, CacheState.mon.h);
838
839 int blur = rofi_theme_get_integer(WIDGET(win), "blur", 0);
840 cairo_t *dr = cairo_create(CacheState.fake_bg);
841 if (CacheState.fake_bgrel) {
842 cairo_set_source_surface(dr, s, 0, 0);
843 } else {
844 cairo_set_source_surface(dr, s, -CacheState.mon.x, -CacheState.mon.y);
845 }
846 cairo_paint(dr);
847 cairo_destroy(dr);
848 cairo_surface_destroy(s);
849 if (blur > 0) {
850 cairo_image_surface_blur(CacheState.fake_bg, blur, 0);
851 TICK_N("BLUR");
852 }
853 }
854 }
855 TICK_N("Fake transparency");
856 }
857}
858
859#ifdef XCB_IMDKIT
860static void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,
861 G_GNUC_UNUSED uint32_t flag, char *str,
862 uint32_t length, G_GNUC_UNUSED uint32_t *keysym,
863 G_GNUC_UNUSED size_t nKeySym,
864 G_GNUC_UNUSED void *user_data) {
866 if (state == NULL) {
867 return;
868 }
869
870#ifndef XCB_IMDKIT_1_0_3_LOWER
871 if (xcb_xim_get_encoding(im) == XCB_XIM_UTF8_STRING) {
872 rofi_view_handle_text(state, str);
873 } else if (xcb_xim_get_encoding(im) == XCB_XIM_COMPOUND_TEXT) {
874 size_t newLength = 0;
875 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
876 if (utf8) {
877 rofi_view_handle_text(state, utf8);
878 }
879 }
880#else
881 size_t newLength = 0;
882 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
883 if (utf8) {
884 rofi_view_handle_text(state, utf8);
885 }
886#endif
887}
888
889static void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,
890 G_GNUC_UNUSED void *user_data) {
891 xcb->ic = 0;
892}
893
894static void create_ic_callback(xcb_xim_t *im, xcb_xic_t new_ic,
895 G_GNUC_UNUSED void *user_data) {
896 xcb->ic = new_ic;
897 if (xcb->ic) {
898 xcb_xim_set_ic_focus(im, xcb->ic);
899 }
900}
901
902gboolean rofi_set_im_window_pos(int new_x, int new_y) {
903 if (!xcb->ic)
904 return false;
905
906 static xcb_point_t spot = {.x = 0, .y = 0};
907 if (spot.x != new_x || spot.y != new_y) {
908 spot.x = new_x;
909 spot.y = new_y;
910 xcb_xim_nested_list nested = xcb_xim_create_nested_list(
911 xcb->im, XCB_XIM_XNSpotLocation, &spot, NULL);
912 xcb_xim_set_ic_values(xcb->im, xcb->ic, NULL, NULL, XCB_XIM_XNClientWindow,
913 &CacheState.main_window, XCB_XIM_XNFocusWindow,
914 &CacheState.main_window, XCB_XIM_XNPreeditAttributes,
915 &nested, NULL);
916 free(nested.data);
917 }
918 return true;
919}
920static void open_xim_callback(xcb_xim_t *im, G_GNUC_UNUSED void *user_data) {
922 uint32_t input_style = XCB_IM_PreeditPosition | XCB_IM_StatusArea;
923 xcb_point_t spot;
924 spot.x = widget_get_x_pos(&state->text->widget) +
926 spot.y = widget_get_y_pos(&state->text->widget) +
927 widget_get_height(&state->text->widget);
928 xcb_xim_nested_list nested =
929 xcb_xim_create_nested_list(im, XCB_XIM_XNSpotLocation, &spot, NULL);
930 xcb_xim_create_ic(
931 im, create_ic_callback, NULL, XCB_XIM_XNInputStyle, &input_style,
932 XCB_XIM_XNClientWindow, &CacheState.main_window, XCB_XIM_XNFocusWindow,
933 &CacheState.main_window, XCB_XIM_XNPreeditAttributes, &nested, NULL);
934 free(nested.data);
935}
936#endif
937
938static void input_history_initialize(void) {
939 if (CacheState.entry_history_enable == FALSE) {
940 return;
941 }
942 CacheState.entry_history = NULL;
943 CacheState.entry_history_index = 0;
944 CacheState.entry_history_length = 0;
945
946 gchar *path = g_build_filename(cache_dir, "rofi-entry-history.txt", NULL);
947 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
948 FILE *fp = fopen(path, "r");
949 if (fp) {
950 char *line = NULL;
951 size_t len = 0;
952 ssize_t nread;
953 while ((nread = getline(&line, &len, fp)) != -1) {
954 CacheState.entry_history = g_realloc(
955 CacheState.entry_history,
956 sizeof(EntryHistoryIndex) * (CacheState.entry_history_length + 1));
957 if (line[nread - 1] == '\n') {
958 line[nread - 1] = '\0';
959 nread--;
960 }
961 CacheState.entry_history[CacheState.entry_history_length].string =
962 g_strdup(line);
963 CacheState.entry_history[CacheState.entry_history_length].index =
964 strlen(line);
965 CacheState.entry_history_length++;
966 CacheState.entry_history_index++;
967 }
968 free(line);
969 fclose(fp);
970 }
971 }
972 g_free(path);
973 CacheState.entry_history = g_realloc(
974 CacheState.entry_history,
975 sizeof(EntryHistoryIndex) * (CacheState.entry_history_length + 1));
976 CacheState.entry_history[CacheState.entry_history_length].string =
977 g_strdup("");
978 CacheState.entry_history[CacheState.entry_history_length].index = 0;
979 CacheState.entry_history_length++;
980}
981static void input_history_save(void) {
982 if (CacheState.entry_history_enable == FALSE) {
983 return;
984 }
985 if (CacheState.entry_history_length > 0) {
986 // History max.
987 int max_history = 20;
988 ThemeWidget *wid = rofi_config_find_widget("entry", NULL, TRUE);
989 if (wid) {
990 Property *p =
991 rofi_theme_find_property(wid, P_INTEGER, "max-history", TRUE);
992 if (p != NULL && p->type == P_INTEGER) {
993 max_history = p->value.i;
994 }
995 }
996 gchar *path = g_build_filename(cache_dir, "rofi-entry-history.txt", NULL);
997 g_debug("Entry filename output: '%s'", path);
998 FILE *fp = fopen(path, "w");
999 if (fp) {
1000 gssize start = MAX(0, (CacheState.entry_history_length - max_history));
1001 for (gssize i = start; i < CacheState.entry_history_length; i++) {
1002 if (strlen(CacheState.entry_history[i].string) > 0) {
1003 fprintf(fp, "%s\n", CacheState.entry_history[i].string);
1004 }
1005 }
1006 fclose(fp);
1007 }
1008 g_free(path);
1009 }
1010 // Cleanups.
1011 if (CacheState.entry_history != NULL) {
1012 for (ssize_t i = 0; i < CacheState.entry_history_length; i++) {
1013 g_free(CacheState.entry_history[i].string);
1014 }
1015 g_free(CacheState.entry_history);
1016 CacheState.entry_history = NULL;
1017 CacheState.entry_history_length = 0;
1018 CacheState.entry_history_index = 0;
1019 }
1020}
1021
1022void __create_window(MenuFlags menu_flags) {
1024
1025 uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
1026 XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |
1027 XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
1028 uint32_t xcb_event_masks =
1029 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
1030 XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS |
1031 XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
1032 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE |
1033 XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;
1034
1035 uint32_t selval[] = {XCB_BACK_PIXMAP_NONE, 0,
1036 XCB_GRAVITY_STATIC, XCB_BACKING_STORE_NOT_USEFUL,
1037 xcb_event_masks, map};
1038
1039#ifdef XCB_IMDKIT
1040 if (config.enable_imdkit) {
1041 xcb_xim_set_im_callback(xcb->im, &xim_callback, NULL);
1042
1043 // Open connection to XIM server.
1044 xcb_xim_open(xcb->im, open_xim_callback, true, NULL);
1045 }
1046#endif
1047
1048 xcb_window_t box_window = xcb_generate_id(xcb->connection);
1049 xcb_void_cookie_t cc = xcb_create_window_checked(
1050 xcb->connection, depth->depth, box_window, xcb_stuff_get_root_window(), 0,
1051 0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visual->visual_id, selmask,
1052 selval);
1053 xcb_generic_error_t *error;
1054 error = xcb_request_check(xcb->connection, cc);
1055 if (error) {
1056 g_error("xcb_create_window() failed error=0x%x\n", error->error_code);
1057 exit(EXIT_FAILURE);
1058 }
1059
1060 TICK_N("xcb create window");
1061 CacheState.gc = xcb_generate_id(xcb->connection);
1062 xcb_create_gc(xcb->connection, CacheState.gc, box_window, 0, 0);
1063
1064 TICK_N("xcb create gc");
1065 // Create a drawable.
1066 CacheState.edit_pixmap = xcb_generate_id(xcb->connection);
1067 xcb_create_pixmap(xcb->connection, depth->depth, CacheState.edit_pixmap,
1068 CacheState.main_window, 200, 100);
1069
1070 CacheState.edit_surf = cairo_xcb_surface_create(
1071 xcb->connection, CacheState.edit_pixmap, visual, 200, 100);
1072 CacheState.edit_draw = cairo_create(CacheState.edit_surf);
1073
1074 TICK_N("create cairo surface");
1075 // Set up pango context.
1076 cairo_font_options_t *fo = cairo_font_options_create();
1077 // Take font description from xlib surface
1078 cairo_surface_get_font_options(CacheState.edit_surf, fo);
1079 // TODO should we update the drawable each time?
1080 PangoContext *p = pango_cairo_create_context(CacheState.edit_draw);
1081 // Set the font options from the xlib surface
1082 pango_cairo_context_set_font_options(p, fo);
1083 TICK_N("pango cairo font setup");
1084
1085 CacheState.main_window = box_window;
1086 CacheState.flags = menu_flags;
1087 monitor_active(&(CacheState.mon));
1088 // Setup dpi
1089 if (config.dpi > 1) {
1090 PangoFontMap *font_map = pango_cairo_font_map_get_default();
1091 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,
1092 (double)config.dpi);
1093 } else if (config.dpi == 0 || config.dpi == 1) {
1094 // Auto-detect mode.
1095 double dpi = 96;
1096 if (CacheState.mon.mh > 0 && config.dpi == 1) {
1097 dpi = (CacheState.mon.h * 25.4) / (double)(CacheState.mon.mh);
1098 } else {
1099 dpi = (xcb->screen->height_in_pixels * 25.4) /
1100 (double)(xcb->screen->height_in_millimeters);
1101 }
1102
1103 g_debug("Auto-detected DPI: %.2lf", dpi);
1104 PangoFontMap *font_map = pango_cairo_font_map_get_default();
1105 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);
1106 config.dpi = dpi;
1107 } else {
1108 // default pango is 96.
1109 PangoFontMap *font_map = pango_cairo_font_map_get_default();
1110 config.dpi =
1111 pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
1112 }
1113 // Setup font.
1114 // Dummy widget.
1115 box *win = box_create(NULL, "window", ROFI_ORIENTATION_HORIZONTAL);
1116 const char *font =
1117 rofi_theme_get_string(WIDGET(win), "font", config.menu_font);
1118 if (font) {
1119 PangoFontDescription *pfd = pango_font_description_from_string(font);
1120 if (helper_validate_font(pfd, font)) {
1121 pango_context_set_font_description(p, pfd);
1122 }
1123 pango_font_description_free(pfd);
1124 }
1125 PangoLanguage *l = pango_language_get_default();
1126 pango_context_set_language(p, l);
1127 TICK_N("configure font");
1128
1129 // Tell textbox to use this context.
1131 // cleanup
1132 g_object_unref(p);
1133 cairo_font_options_destroy(fo);
1134
1135 TICK_N("textbox setup");
1136 // // make it an unmanaged window
1137 if (((menu_flags & MENU_TRANSIENT_WINDOW) != 0)) {
1138 xcb_atom_t atoms[] = {xcb->ewmh._NET_WM_STATE_MODAL};
1139
1140 window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE, atoms,
1141 sizeof(atoms) / sizeof(xcb_atom_t));
1142 window_set_atom_prop(box_window, xcb->ewmh._NET_WM_WINDOW_TYPE,
1143 &(xcb->ewmh._NET_WM_WINDOW_TYPE_UTILITY), 1);
1144 x11_disable_decoration(box_window);
1145
1146 xcb_window_t active_window;
1147 xcb_get_property_cookie_t awc;
1148 awc = xcb_ewmh_get_active_window(&xcb->ewmh, xcb->screen_nbr);
1149
1150 if (xcb_ewmh_get_active_window_reply(&xcb->ewmh, awc, &active_window,
1151 NULL)) {
1152 xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE, box_window,
1153 XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1,
1154 &active_window);
1155 }
1156 } else if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {
1157 window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE,
1158 &(xcb->ewmh._NET_WM_STATE_ABOVE), 1);
1159 uint32_t values[] = {1};
1160 xcb_change_window_attributes(xcb->connection, box_window,
1161 XCB_CW_OVERRIDE_REDIRECT, values);
1162 } else {
1163 window_set_atom_prop(box_window, xcb->ewmh._NET_WM_WINDOW_TYPE,
1164 &(xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL), 1);
1165 x11_disable_decoration(box_window);
1166 }
1167
1168 TICK_N("setup window attributes");
1169 CacheState.fullscreen =
1170 rofi_theme_get_boolean(WIDGET(win), "fullscreen", FALSE);
1171 if (CacheState.fullscreen) {
1172 xcb_atom_t atoms[] = {xcb->ewmh._NET_WM_STATE_FULLSCREEN,
1173 xcb->ewmh._NET_WM_STATE_ABOVE};
1174 window_set_atom_prop(box_window, xcb->ewmh._NET_WM_STATE, atoms,
1175 sizeof(atoms) / sizeof(xcb_atom_t));
1176 }
1177
1178 xcb_atom_t protocols[] = {netatoms[WM_TAKE_FOCUS]};
1179 xcb_icccm_set_wm_protocols(xcb->connection, box_window,
1180 xcb->ewmh.WM_PROTOCOLS, G_N_ELEMENTS(protocols),
1181 protocols);
1182
1183 TICK_N("setup window fullscreen");
1184 // Set the WM_NAME
1186 const char wm_class_name[] = "rofi\0Rofi";
1187 xcb_icccm_set_wm_class(xcb->connection, box_window, sizeof(wm_class_name),
1188 wm_class_name);
1189
1190 TICK_N("setup window name and class");
1191 const char *transparency =
1192 rofi_theme_get_string(WIDGET(win), "transparency", NULL);
1193 if (transparency) {
1194 rofi_view_setup_fake_transparency(WIDGET(win), transparency);
1195 }
1196 if (xcb->sncontext != NULL) {
1197 sn_launchee_context_setup_window(xcb->sncontext, CacheState.main_window);
1198 }
1199 TICK_N("setup startup notification");
1200 widget_free(WIDGET(win));
1201 TICK_N("done");
1202
1203 // Set the PID.
1204 pid_t pid = getpid();
1205 xcb_ewmh_set_wm_pid(&(xcb->ewmh), CacheState.main_window, pid);
1206
1207 // Get hostname
1208 const char *hostname = g_get_host_name();
1209 char *ahost = g_hostname_to_ascii(hostname);
1210 if (ahost != NULL) {
1211 xcb_icccm_set_wm_client_machine(xcb->connection, CacheState.main_window,
1212 XCB_ATOM_STRING, 8, strlen(ahost), ahost);
1213 g_free(ahost);
1214 }
1215}
1216
1223 if (CacheState.fullscreen) {
1224 state->width = CacheState.mon.w;
1225 return;
1226 }
1227 // Calculate as float to stop silly, big rounding down errors.
1228 state->width = (CacheState.mon.w / 100.0f) * DEFAULT_MENU_WIDTH;
1229 // Use theme configured width, if set.
1231 "width", state->width);
1233}
1234
1238
1245 if (state->filtered_lines == 1) {
1246 state->retv = MENU_OK;
1247 (state->selected_line) =
1249 state->quit = 1;
1250 return;
1251 }
1252
1253 // Double tab!
1254 if (state->filtered_lines == 0 && ROW_TAB == state->prev_action) {
1255 state->retv = MENU_NEXT;
1256 (state->selected_line) = 0;
1257 state->quit = TRUE;
1258 } else {
1260 }
1261 state->prev_action = ROW_TAB;
1262}
1263
1268inline static void rofi_view_nav_row_select(RofiViewState *state) {
1269 if (state->list_view == NULL) {
1270 return;
1271 }
1272 unsigned int selected = listview_get_selected(state->list_view);
1273 // If a valid item is selected, return that..
1274 if (selected < state->filtered_lines) {
1275 char *str = mode_get_completion(state->sw, state->line_map[selected]);
1276 textbox_text(state->text, str);
1277 g_free(str);
1279 state->refilter = TRUE;
1280 }
1281}
1282
1288inline static void rofi_view_nav_first(RofiViewState *state) {
1289 // state->selected = 0;
1291}
1292
1298inline static void rofi_view_nav_last(RofiViewState *state) {
1299 // If no lines, do nothing.
1300 if (state->filtered_lines == 0) {
1301 return;
1302 }
1303 // state->selected = state->filtered_lines - 1;
1304 listview_set_selected(state->list_view, -1);
1305}
1306static void selection_changed_user_callback(unsigned int index,
1307 RofiViewState *state) {
1308 if (config.on_selection_changed == NULL)
1309 return;
1310
1311 int fstate = 0;
1312 char *text = mode_get_display_value(state->sw, state->line_map[index],
1313 &fstate, NULL, TRUE);
1314 char **args = NULL;
1315 int argv = 0;
1316 helper_parse_setup(config.on_selection_changed, &args, &argv, "{entry}", text,
1317 (char *)0);
1318 if (args != NULL)
1319 helper_execute(NULL, args, "", config.on_selection_changed, NULL);
1320 g_free(text);
1321}
1322static void selection_changed_callback(G_GNUC_UNUSED listview *lv,
1323 unsigned int index, void *udata) {
1324 RofiViewState *state = (RofiViewState *)udata;
1325 if (index < state->filtered_lines) {
1326 if (state->previous_line != state->line_map[index]) {
1327 selection_changed_user_callback(index, state);
1328 state->previous_line = state->line_map[index];
1329 }
1330 }
1331 if (state->tb_current_entry) {
1332 if (index < state->filtered_lines) {
1333 int fstate = 0;
1334 char *text = mode_get_display_value(state->sw, state->line_map[index],
1335 &fstate, NULL, TRUE);
1336 textbox_text(state->tb_current_entry, text);
1337 g_free(text);
1338 } else {
1339 textbox_text(state->tb_current_entry, "");
1340 }
1341 }
1342 if (state->icon_current_entry) {
1343 if (index < state->filtered_lines) {
1344 int icon_height =
1346 WIDGET(state->icon_current_entry)->w);
1347 cairo_surface_t *surf_icon =
1348 mode_get_icon(state->sw, state->line_map[index], icon_height);
1349 icon_set_surface(state->icon_current_entry, surf_icon);
1350 } else {
1352 }
1353 }
1354}
1355static void update_callback(textbox *t, icon *ico, unsigned int index,
1356 void *udata, TextBoxFontType *type, gboolean full) {
1357 RofiViewState *state = (RofiViewState *)udata;
1358 if (full) {
1359 GList *add_list = NULL;
1360 int fstate = 0;
1361 char *text = mode_get_display_value(state->sw, state->line_map[index],
1362 &fstate, &add_list, TRUE);
1363 (*type) |= fstate;
1364
1365 if (ico) {
1366 int icon_height = widget_get_desired_height(WIDGET(ico), WIDGET(ico)->w);
1367 cairo_surface_t *surf_icon =
1368 mode_get_icon(state->sw, state->line_map[index], icon_height);
1369 icon_set_surface(ico, surf_icon);
1370 }
1371 if (t) {
1372 // TODO needed for markup.
1373 textbox_font(t, *type);
1374 // Move into list view.
1375 textbox_text(t, text);
1376 PangoAttrList *list = textbox_get_pango_attributes(t);
1377 if (list != NULL) {
1378 pango_attr_list_ref(list);
1379 } else {
1380 list = pango_attr_list_new();
1381 }
1382
1383 if (state->tokens) {
1385 {0.0, 0.0, 0.0, 0.0}};
1386 th = rofi_theme_get_highlight(WIDGET(t), "highlight", th);
1388 textbox_get_visible_text(t), list);
1389 }
1390 for (GList *iter = g_list_first(add_list); iter != NULL;
1391 iter = g_list_next(iter)) {
1392 pango_attr_list_insert(list, (PangoAttribute *)(iter->data));
1393 }
1395 pango_attr_list_unref(list);
1396 }
1397
1398 g_list_free(add_list);
1399 g_free(text);
1400 } else {
1401 // Never called.
1402 int fstate = 0;
1403 mode_get_display_value(state->sw, state->line_map[index], &fstate, NULL,
1404 FALSE);
1405 (*type) |= fstate;
1406 // TODO needed for markup.
1407 textbox_font(t, *type);
1408 }
1409}
1414
1415void rofi_view_update(RofiViewState *state, gboolean qr) {
1416 if (!widget_need_redraw(WIDGET(state->main_window))) {
1417 return;
1418 }
1419 g_debug("Redraw view");
1420 TICK();
1421 cairo_t *d = CacheState.edit_draw;
1422 cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);
1423 if (CacheState.fake_bg != NULL) {
1424 if (CacheState.fake_bgrel) {
1425 cairo_set_source_surface(d, CacheState.fake_bg, 0.0, 0.0);
1426 } else {
1427 cairo_set_source_surface(d, CacheState.fake_bg,
1428 (double)(CacheState.mon.x - state->x),
1429 (double)(CacheState.mon.y - state->y));
1430 }
1431 } else {
1432 // Paint the background transparent.
1433 cairo_set_source_rgba(d, 0, 0, 0, 0.0);
1434 }
1435 cairo_paint(d);
1436 // Always paint as overlay over the background.
1437 cairo_set_operator(d, CAIRO_OPERATOR_OVER);
1438
1439 TICK_N("Background");
1440 widget_draw(WIDGET(state->main_window), d);
1441
1442#ifdef XCB_IMDKIT
1443 if (config.enable_imdkit) {
1444 int x = widget_get_x_pos(&state->text->widget) +
1446 int y = widget_get_y_pos(&state->text->widget) +
1447 widget_get_height(&state->text->widget);
1449 }
1450#endif
1451
1452 TICK_N("widgets");
1453 cairo_surface_flush(CacheState.edit_surf);
1454 if (qr) {
1456 }
1457}
1458
1460 g_free(state->line_map);
1461 g_free(state->distance);
1462 state->num_lines = mode_get_num_entries(state->sw);
1463 state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));
1464 state->distance = g_malloc0_n(state->num_lines, sizeof(int));
1467}
1468
1470 CacheState.refilter_timeout = 0;
1471 CacheState.refilter_timeout_count = 0;
1472 if (state->sw == NULL) {
1473 return G_SOURCE_REMOVE;
1474 }
1475 GTimer *timer = g_timer_new();
1476 TICK_N("Filter start");
1477 if (state->reload) {
1478 _rofi_view_reload_row(state);
1479 state->reload = FALSE;
1480 }
1481 TICK_N("Filter reload rows");
1482 if (state->tokens) {
1484 state->tokens = NULL;
1485 }
1486 TICK_N("Filter tokenize");
1487 if (state->text && strlen(state->text->text) > 0) {
1488
1489 listview_set_filtered(state->list_view, TRUE);
1490 unsigned int j = 0;
1491 gchar *pattern = mode_preprocess_input(state->sw, state->text->text);
1492 glong plen = pattern ? g_utf8_strlen(pattern, -1) : 0;
1494 state->tokens = helper_tokenize(pattern, state->case_sensitive);
1495
1496 if (config.case_smart && state->case_indicator) {
1498 }
1506 unsigned int nt = MAX(1, state->num_lines / 500);
1507 // Limit the number of jobs, it could cause stack overflow if we don´t
1508 // limit.
1509 nt = MIN(nt, config.threads * 4);
1510 thread_state_view states[nt];
1511 GCond cond;
1512 GMutex mutex;
1513 g_mutex_init(&mutex);
1514 g_cond_init(&cond);
1515 unsigned int count = nt;
1516 unsigned int steps = (state->num_lines + nt) / nt;
1517 for (unsigned int i = 0; i < nt; i++) {
1518 states[i].state = state;
1519 states[i].start = i * steps;
1520 states[i].stop = MIN(state->num_lines, (i + 1) * steps);
1521 states[i].count = 0;
1522 states[i].cond = &cond;
1523 states[i].mutex = &mutex;
1524 states[i].acount = &count;
1525 states[i].plen = plen;
1526 states[i].pattern = pattern;
1527 states[i].st.callback = filter_elements;
1528 states[i].st.free = NULL;
1529 states[i].st.priority = G_PRIORITY_HIGH;
1530 if (i > 0) {
1531 g_thread_pool_push(tpool, &states[i], NULL);
1532 }
1533 }
1534 // Run one in this thread.
1535 rofi_view_call_thread(&states[0], NULL);
1536 // No need to do this with only one thread.
1537 if (nt > 1) {
1538 g_mutex_lock(&mutex);
1539 while (count > 0) {
1540 g_cond_wait(&cond, &mutex);
1541 }
1542 g_mutex_unlock(&mutex);
1543 }
1544 g_cond_clear(&cond);
1545 g_mutex_clear(&mutex);
1546 for (unsigned int i = 0; i < nt; i++) {
1547 if (j != states[i].start) {
1548 memmove(&(state->line_map[j]), &(state->line_map[states[i].start]),
1549 sizeof(unsigned int) * (states[i].count));
1550 }
1551 j += states[i].count;
1552 }
1553 if (config.sort) {
1554 g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
1555 state->distance);
1556 }
1557
1558 // Cleanup + bookkeeping.
1559 state->filtered_lines = j;
1560 g_free(pattern);
1561
1562 double elapsed = g_timer_elapsed(timer, NULL);
1563
1564 CacheState.max_refilter_time = elapsed;
1565 } else {
1566 listview_set_filtered(state->list_view, FALSE);
1567 for (unsigned int i = 0; i < state->num_lines; i++) {
1568 state->line_map[i] = i;
1569 }
1570 state->filtered_lines = state->num_lines;
1571 }
1572 TICK_N("Filter matching done");
1574
1575 if (state->tb_filtered_rows) {
1576 char *r = g_strdup_printf("%u", state->filtered_lines);
1577 textbox_text(state->tb_filtered_rows, r);
1578 g_free(r);
1579 }
1580 if (state->tb_total_rows) {
1581 char *r = g_strdup_printf("%u", state->num_lines);
1582 textbox_text(state->tb_total_rows, r);
1583 g_free(r);
1584 }
1585 TICK_N("Update filter lines");
1586
1587 if (config.auto_select == TRUE && state->filtered_lines == 1 &&
1588 state->num_lines > 1) {
1589 (state->selected_line) =
1591 state->retv = MENU_OK;
1592 state->quit = TRUE;
1593 }
1594
1595 // Size the window.
1596 int height = rofi_view_calculate_height(state);
1597 if (height != state->height) {
1598 state->height = height;
1601 g_debug("Resize based on re-filter");
1602 }
1603 TICK_N("Filter resize window based on window ");
1604 state->refilter = FALSE;
1605 TICK_N("Filter done");
1606 rofi_view_update(state, TRUE);
1607
1608 g_timer_destroy(timer);
1609 return G_SOURCE_REMOVE;
1610}
1612 CacheState.refilter_timeout_count++;
1613 if (CacheState.refilter_timeout != 0) {
1614
1615 g_source_remove(CacheState.refilter_timeout);
1616 CacheState.refilter_timeout = 0;
1617 }
1618 if (CacheState.max_refilter_time > (config.refilter_timeout_limit / 1000.0) &&
1619 state->text && strlen(state->text->text) > 0 &&
1620 CacheState.refilter_timeout_count < 25) {
1621 if (CacheState.delayed_mode == FALSE) {
1622 g_warning(
1623 "Filtering took %f seconds ( %f ), switching to delayed filter\n",
1624 CacheState.max_refilter_time, config.refilter_timeout_limit / 1000.0);
1625 CacheState.delayed_mode = TRUE;
1626 }
1627 CacheState.refilter_timeout =
1628 g_timeout_add(200, (GSourceFunc)rofi_view_refilter_real, state);
1629 } else {
1630 if (CacheState.delayed_mode == TRUE && state->text &&
1631 strlen(state->text->text) > 0 &&
1632 CacheState.refilter_timeout_count < 25) {
1633 g_warning(
1634 "Filtering took %f seconds , switching back to instant filter\n",
1635 CacheState.max_refilter_time);
1636 CacheState.delayed_mode = FALSE;
1637 }
1639 }
1640}
1642 if (CacheState.refilter_timeout != 0) {
1643 g_source_remove(CacheState.refilter_timeout);
1644 CacheState.refilter_timeout = 0;
1645 }
1646 if (state->refilter) {
1648 }
1649}
1650
1655void process_result(RofiViewState *state);
1657 if (state && state->finalize != NULL) {
1658 state->finalize(state);
1659 }
1660}
1661
1666static void rofi_view_input_changed(void) {
1667 rofi_view_take_action("inputchange");
1668
1670 if (CacheState.entry_history_enable && state) {
1671 if (CacheState.entry_history[CacheState.entry_history_index].string !=
1672 NULL) {
1673 g_free(CacheState.entry_history[CacheState.entry_history_index].string);
1674 }
1675 CacheState.entry_history[CacheState.entry_history_index].string =
1676 textbox_get_text(state->text);
1677 CacheState.entry_history[CacheState.entry_history_index].index =
1678 textbox_get_cursor(state->text);
1679 }
1680}
1681
1684 switch (action) {
1685 // Handling of paste
1686 case PASTE_PRIMARY:
1687 xcb_convert_selection(xcb->connection, CacheState.main_window,
1688 XCB_ATOM_PRIMARY, xcb->ewmh.UTF8_STRING,
1689 xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1690 xcb_flush(xcb->connection);
1691 break;
1692 case PASTE_SECONDARY:
1693 xcb_convert_selection(xcb->connection, CacheState.main_window,
1694 netatoms[CLIPBOARD], xcb->ewmh.UTF8_STRING,
1695 xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1696 xcb_flush(xcb->connection);
1697 break;
1698 case COPY_SECONDARY: {
1699 char *data = NULL;
1700 unsigned int selected = listview_get_selected(state->list_view);
1701 if (selected < state->filtered_lines) {
1702 data = mode_get_completion(state->sw, state->line_map[selected]);
1703 } else if (state->text && state->text->text) {
1704 data = g_strdup(state->text->text);
1705 }
1706 if (data) {
1708 xcb_set_selection_owner(xcb->connection, CacheState.main_window,
1709 netatoms[CLIPBOARD], XCB_CURRENT_TIME);
1710 xcb_flush(xcb->connection);
1711 }
1712 } break;
1713 case SCREENSHOT:
1715 break;
1716 case CHANGE_ELLIPSIZE:
1717 if (state->list_view) {
1719 }
1720 break;
1721 case TOGGLE_SORT:
1722 if (state->case_indicator != NULL) {
1723 config.sort = !config.sort;
1724 state->refilter = TRUE;
1726 }
1727 break;
1728 case MODE_PREVIOUS:
1729 state->retv = MENU_PREVIOUS;
1730 (state->selected_line) = 0;
1731 state->quit = TRUE;
1732 break;
1733 // Menu navigation.
1734 case MODE_NEXT:
1735 state->retv = MENU_NEXT;
1736 (state->selected_line) = 0;
1737 state->quit = TRUE;
1738 break;
1739 case MODE_COMPLETE: {
1740 unsigned int selected = listview_get_selected(state->list_view);
1741 state->selected_line = UINT32_MAX;
1742 if (selected < state->filtered_lines) {
1743 state->selected_line = state->line_map[selected];
1744 }
1745 state->retv = MENU_COMPLETE;
1746 state->quit = TRUE;
1747 break;
1748 }
1749 // Toggle case sensitivity.
1751 if (state->case_indicator != NULL) {
1752 config.case_sensitive = !config.case_sensitive;
1753 (state->selected_line) = 0;
1754 state->refilter = TRUE;
1756 }
1757 break;
1758 // Special delete entry command.
1759 case DELETE_ENTRY: {
1760 unsigned int selected = listview_get_selected(state->list_view);
1761 if (selected < state->filtered_lines) {
1762 (state->selected_line) = state->line_map[selected];
1763 state->retv = MENU_ENTRY_DELETE;
1764 state->quit = TRUE;
1765 }
1766 break;
1767 }
1768 case SELECT_ELEMENT_1:
1769 case SELECT_ELEMENT_2:
1770 case SELECT_ELEMENT_3:
1771 case SELECT_ELEMENT_4:
1772 case SELECT_ELEMENT_5:
1773 case SELECT_ELEMENT_6:
1774 case SELECT_ELEMENT_7:
1775 case SELECT_ELEMENT_8:
1776 case SELECT_ELEMENT_9:
1777 case SELECT_ELEMENT_10: {
1778 unsigned int index = action - SELECT_ELEMENT_1;
1779 if (index < state->filtered_lines) {
1780 state->selected_line = state->line_map[index];
1781 state->retv = MENU_OK;
1782 state->quit = TRUE;
1783 }
1784 break;
1785 }
1786 case CUSTOM_1:
1787 case CUSTOM_2:
1788 case CUSTOM_3:
1789 case CUSTOM_4:
1790 case CUSTOM_5:
1791 case CUSTOM_6:
1792 case CUSTOM_7:
1793 case CUSTOM_8:
1794 case CUSTOM_9:
1795 case CUSTOM_10:
1796 case CUSTOM_11:
1797 case CUSTOM_12:
1798 case CUSTOM_13:
1799 case CUSTOM_14:
1800 case CUSTOM_15:
1801 case CUSTOM_16:
1802 case CUSTOM_17:
1803 case CUSTOM_18:
1804 case CUSTOM_19: {
1805 state->selected_line = UINT32_MAX;
1806 unsigned int selected = listview_get_selected(state->list_view);
1807 if (selected < state->filtered_lines) {
1808 (state->selected_line) = state->line_map[selected];
1809 }
1810 state->retv = MENU_CUSTOM_COMMAND | ((action - CUSTOM_1) & MENU_LOWER_MASK);
1811 state->quit = TRUE;
1812 break;
1813 }
1814 // If you add a binding here, make sure to add it to
1815 // rofi_view_keyboard_navigation too
1816 case CANCEL:
1817 state->retv = MENU_CANCEL;
1818 state->quit = TRUE;
1819 break;
1820 case ELEMENT_NEXT:
1822 break;
1823 case ELEMENT_PREV:
1825 break;
1826 case ROW_UP:
1827 listview_nav_up(state->list_view);
1828 break;
1829 case ROW_TAB:
1830 rofi_view_nav_row_tab(state);
1831 break;
1832 case ROW_DOWN:
1834 break;
1835 case ROW_LEFT:
1837 break;
1838 case ROW_RIGHT:
1840 break;
1841 case PAGE_PREV:
1843 break;
1844 case PAGE_NEXT:
1846 break;
1847 case ROW_FIRST:
1848 rofi_view_nav_first(state);
1849 break;
1850 case ROW_LAST:
1851 rofi_view_nav_last(state);
1852 break;
1853 case ROW_SELECT:
1855 break;
1856 // If you add a binding here, make sure to add it to textbox_keybinding too
1857 case MOVE_CHAR_BACK: {
1858 if (textbox_keybinding(state->text, action) == 0) {
1860 }
1861 break;
1862 }
1863 case MOVE_CHAR_FORWARD: {
1864 if (textbox_keybinding(state->text, action) == 0) {
1866 }
1867 break;
1868 }
1869 case CLEAR_LINE:
1870 case MOVE_FRONT:
1871 case MOVE_END:
1872 case REMOVE_TO_EOL:
1873 case REMOVE_TO_SOL:
1874 case REMOVE_WORD_BACK:
1877 case MOVE_WORD_BACK:
1878 case MOVE_WORD_FORWARD:
1879 case REMOVE_CHAR_BACK: {
1880 int rc = textbox_keybinding(state->text, action);
1881 if (rc == 1) {
1882 // Entry changed.
1883 state->refilter = TRUE;
1885 } else if (rc == 2) {
1886 // Movement.
1887 }
1888 break;
1889 }
1890 case ACCEPT_ALT: {
1892 unsigned int selected = listview_get_selected(state->list_view);
1893 state->selected_line = UINT32_MAX;
1894 if (selected < state->filtered_lines) {
1895 (state->selected_line) = state->line_map[selected];
1896 state->retv = MENU_OK;
1897 } else {
1898 // Nothing entered and nothing selected.
1899 state->retv = MENU_CUSTOM_INPUT;
1900 }
1901 state->retv |= MENU_CUSTOM_ACTION;
1902 state->quit = TRUE;
1903 break;
1904 }
1905 case ACCEPT_CUSTOM: {
1907 state->selected_line = UINT32_MAX;
1908 state->retv = MENU_CUSTOM_INPUT;
1909 state->quit = TRUE;
1910 break;
1911 }
1912 case ACCEPT_CUSTOM_ALT: {
1914 state->selected_line = UINT32_MAX;
1916 state->quit = TRUE;
1917 break;
1918 }
1919 case ACCEPT_ENTRY: {
1921 // If a valid item is selected, return that..
1922 unsigned int selected = listview_get_selected(state->list_view);
1923 state->selected_line = UINT32_MAX;
1924 if (selected < state->filtered_lines) {
1925 (state->selected_line) = state->line_map[selected];
1926 state->retv = MENU_OK;
1927 } else {
1928 // Nothing entered and nothing selected.
1929 state->retv = MENU_CUSTOM_INPUT;
1930 }
1931 state->quit = TRUE;
1932 break;
1933 }
1934 case ENTRY_HISTORY_DOWN: {
1935 if (CacheState.entry_history_enable && state->text) {
1936 CacheState.entry_history[CacheState.entry_history_index].index =
1937 textbox_get_cursor(state->text);
1938 if (CacheState.entry_history_index > 0) {
1939 CacheState.entry_history_index--;
1940 }
1941 if (state->text) {
1943 state->text,
1944 CacheState.entry_history[CacheState.entry_history_index].string);
1946 state->text,
1947 CacheState.entry_history[CacheState.entry_history_index].index);
1948 state->refilter = TRUE;
1949 }
1950 }
1951 break;
1952 }
1953 case ENTRY_HISTORY_UP: {
1954 if (CacheState.entry_history_enable && state->text) {
1955 if (CacheState.entry_history[CacheState.entry_history_index].string !=
1956 NULL) {
1957 g_free(CacheState.entry_history[CacheState.entry_history_index].string);
1958 }
1959 CacheState.entry_history[CacheState.entry_history_index].string =
1960 textbox_get_text(state->text);
1961 CacheState.entry_history[CacheState.entry_history_index].index =
1962 textbox_get_cursor(state->text);
1963 // Don't create up if current is empty.
1964 if (strlen(
1965 CacheState.entry_history[CacheState.entry_history_index].string) >
1966 0) {
1967 CacheState.entry_history_index++;
1968 if (CacheState.entry_history_index >= CacheState.entry_history_length) {
1969 CacheState.entry_history =
1970 g_realloc(CacheState.entry_history,
1971 sizeof(EntryHistoryIndex) *
1972 (CacheState.entry_history_length + 1));
1973 CacheState.entry_history[CacheState.entry_history_length].string =
1974 g_strdup("");
1975 CacheState.entry_history[CacheState.entry_history_length].index = 0;
1976 CacheState.entry_history_length++;
1977 }
1978 }
1980 state->text,
1981 CacheState.entry_history[CacheState.entry_history_index].string);
1983 state->text,
1984 CacheState.entry_history[CacheState.entry_history_index].index);
1985 state->refilter = TRUE;
1986 }
1987 break;
1988 }
1989 case MATCHER_UP:
1991 rofi_view_refilter(state);
1993 break;
1994 case MATCHER_DOWN:
1996 rofi_view_refilter(state);
1998 break;
1999 }
2000}
2001
2003 guint action) {
2004 switch (scope) {
2005 case SCOPE_GLOBAL:
2006 return TRUE;
2012 gint x = state->mouse.x, y = state->mouse.y;
2014 (WidgetType)scope, x, y);
2015 if (target == NULL) {
2016 return FALSE;
2017 }
2018 widget_xy_to_relative(target, &x, &y);
2019 switch (widget_check_action(target, action, x, y)) {
2021 return FALSE;
2025 return TRUE;
2026 }
2027 break;
2028 }
2029 }
2030 return FALSE;
2031}
2032
2034 guint action) {
2036 switch (scope) {
2037 case SCOPE_GLOBAL:
2039 return;
2045 gint x = state->mouse.x, y = state->mouse.y;
2046 // If we already captured a motion, always forward action to this widget.
2047 widget *target = state->mouse.motion_target;
2048 // If we have not a previous captured motion, lookup widget.
2049 if (target == NULL) {
2051 (WidgetType)scope, x, y);
2052 }
2053 if (target == NULL) {
2054 return;
2055 }
2056 widget_xy_to_relative(target, &x, &y);
2057 switch (widget_trigger_action(target, action, x, y)) {
2059 return;
2061 target = NULL;
2064 state->mouse.motion_target = target;
2067 return;
2068 }
2069 break;
2070 }
2071 }
2072}
2073
2074void rofi_view_handle_text(RofiViewState *state, char *text) {
2075 if (textbox_append_text(state->text, text, strlen(text))) {
2076 state->refilter = TRUE;
2078 }
2079}
2080
2082 switch (type) {
2084 return CURSOR_DEFAULT;
2085
2087 return CURSOR_POINTER;
2088
2089 case ROFI_CURSOR_TEXT:
2090 return CURSOR_TEXT;
2091 }
2092
2093 return CURSOR_DEFAULT;
2094}
2095
2097 gint y) {
2099 WIDGET_TYPE_UNKNOWN, x, y);
2100
2101 return target != NULL ? target->cursor_type : ROFI_CURSOR_DEFAULT;
2102}
2103
2106
2107 if (x11_type == CacheState.cursor_type) {
2108 return;
2109 }
2110
2111 CacheState.cursor_type = x11_type;
2112
2113 x11_set_cursor(CacheState.main_window, x11_type);
2114}
2115
2117 gboolean find_mouse_target) {
2118 state->mouse.x = x;
2119 state->mouse.y = y;
2120
2122
2124
2125 if (find_mouse_target) {
2128
2129 if (target != NULL) {
2130 state->mouse.motion_target = target;
2131 }
2132 }
2133
2134 if (state->mouse.motion_target != NULL) {
2137
2138 if (find_mouse_target) {
2139 state->mouse.motion_target = NULL;
2140 }
2141 }
2142}
2143
2145 if (state->retv & MENU_OK) {
2146 if (config.on_entry_accepted == NULL)
2147 return;
2148 int fstate = 0;
2149 unsigned int selected = listview_get_selected(state->list_view);
2150 // TODO: handle custom text
2151 if (selected >= state->filtered_lines)
2152 return;
2153 // Pass selected text to custom command
2154 char *text = mode_get_display_value(state->sw, state->line_map[selected],
2155 &fstate, NULL, TRUE);
2156 char **args = NULL;
2157 int argv = 0;
2158 helper_parse_setup(config.on_entry_accepted, &args, &argv, "{entry}", text,
2159 (char *)0);
2160 if (args != NULL)
2161 helper_execute(NULL, args, "", config.on_entry_accepted, NULL);
2162 g_free(text);
2163 } else if (state->retv & MENU_CANCEL) {
2164 if (config.on_menu_canceled == NULL)
2165 return;
2166 helper_execute_command(NULL, config.on_menu_canceled, FALSE, NULL);
2167 } else if (state->retv & MENU_NEXT || state->retv & MENU_PREVIOUS ||
2168 state->retv & MENU_QUICK_SWITCH || state->retv & MENU_COMPLETE) {
2169 if (config.on_mode_changed == NULL)
2170 return;
2171 // TODO: pass mode name to custom command
2172 helper_execute_command(NULL, config.on_mode_changed, FALSE, NULL);
2173 }
2174}
2176 if (rofi_view_get_completed(state)) {
2177 // Exec custom user commands
2179 // This menu is done.
2180 rofi_view_finalize(state);
2181 // If there a state. (for example error) reload it.
2182 state = rofi_view_get_active();
2183
2184 // cleanup, if no more state to display.
2185 if (state == NULL) {
2186 // Quit main-loop.
2188 return;
2189 }
2190 }
2191
2192 // Update if requested.
2193 if (state->refilter) {
2194 rofi_view_refilter(state);
2195 }
2196 rofi_view_update(state, TRUE);
2197 return;
2198}
2199
2205 xcb_configure_notify_event_t *xce) {
2206 if (xce->window == CacheState.main_window) {
2207 if (state->x != xce->x || state->y != xce->y) {
2208 state->x = xce->x;
2209 state->y = xce->y;
2211 }
2212 if (state->width != xce->width || state->height != xce->height) {
2213 state->width = xce->width;
2214 state->height = xce->height;
2215
2216 cairo_destroy(CacheState.edit_draw);
2217 cairo_surface_destroy(CacheState.edit_surf);
2218
2219 xcb_free_pixmap(xcb->connection, CacheState.edit_pixmap);
2220 CacheState.edit_pixmap = xcb_generate_id(xcb->connection);
2221 xcb_create_pixmap(xcb->connection, depth->depth, CacheState.edit_pixmap,
2222 CacheState.main_window, state->width, state->height);
2223
2224 CacheState.edit_surf =
2225 cairo_xcb_surface_create(xcb->connection, CacheState.edit_pixmap,
2226 visual, state->width, state->height);
2227 CacheState.edit_draw = cairo_create(CacheState.edit_surf);
2228 g_debug("Re-size window based external request: %d %d", state->width,
2229 state->height);
2230 widget_resize(WIDGET(state->main_window), state->width, state->height);
2231 }
2232 }
2233}
2234
2238void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target) {
2239 if ((CacheState.flags & MENU_NORMAL_WINDOW) == 0) {
2240 if (target != CacheState.main_window) {
2241 state->quit = TRUE;
2242 state->retv = MENU_CANCEL;
2243 }
2244 }
2245}
2246
2248 if (CacheState.repaint_source == 0) {
2249 CacheState.count++;
2250 g_debug("redraw %llu", CacheState.count);
2251 CacheState.repaint_source =
2252 g_idle_add_full(G_PRIORITY_HIGH_IDLE, rofi_view_repaint, NULL, NULL);
2253 }
2254}
2255
2257 if (CacheState.fullscreen == TRUE) {
2258 return CacheState.mon.h;
2259 }
2260
2261 RofiDistance h =
2262 rofi_theme_get_distance(WIDGET(state->main_window), "height", 0);
2263 unsigned int height = distance_get_pixel(h, ROFI_ORIENTATION_VERTICAL);
2264 // If height is set, return it.
2265 if (height > 0) {
2266 return height;
2267 }
2268 // Autosize based on widgets.
2271}
2272
2274 widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
2275 G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
2276 RofiViewState *state = (RofiViewState *)user_data;
2277 switch (action) {
2278 case MOUSE_CLICK_DOWN: {
2279 const char *type = rofi_theme_get_string(wid, "action", NULL);
2280 if (type) {
2281 if (state->list_view) {
2282 (state->selected_line) =
2284 } else {
2285 (state->selected_line) = UINT32_MAX;
2286 }
2287 guint id = key_binding_get_action_from_name(type);
2288 if (id != UINT32_MAX) {
2290 }
2291 state->skip_absorb = TRUE;
2293 }
2294 }
2295 case MOUSE_CLICK_UP:
2296 case MOUSE_DCLICK_DOWN:
2297 case MOUSE_DCLICK_UP:
2298 break;
2299 }
2301}
2303 widget *wid, MouseBindingMouseDefaultAction action, G_GNUC_UNUSED gint x,
2304 G_GNUC_UNUSED gint y, G_GNUC_UNUSED void *user_data) {
2305 RofiViewState *state = (RofiViewState *)user_data;
2306 unsigned int i;
2307 for (i = 0; i < state->num_modes; i++) {
2308 if (WIDGET(state->modes[i]) == wid) {
2309 break;
2310 }
2311 }
2312 if (i == state->num_modes) {
2314 }
2315
2316 switch (action) {
2317 case MOUSE_CLICK_DOWN:
2318 state->retv = MENU_QUICK_SWITCH | (i & MENU_LOWER_MASK);
2319 state->quit = TRUE;
2320 state->skip_absorb = TRUE;
2322 case MOUSE_CLICK_UP:
2323 case MOUSE_DCLICK_DOWN:
2324 case MOUSE_DCLICK_UP:
2325 break;
2326 }
2328}
2329
2330// @TODO don't like this construction.
2331static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom,
2332 void *udata) {
2333 RofiViewState *state = (RofiViewState *)udata;
2334 state->retv = MENU_OK;
2335 if (custom) {
2336 state->retv |= MENU_CUSTOM_ACTION;
2337 }
2338 (state->selected_line) = state->line_map[listview_get_selected(lv)];
2339 // Quit
2340 state->quit = TRUE;
2341 state->skip_absorb = TRUE;
2342}
2343
2344static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget,
2345 const char *name) {
2346 char *defaults = NULL;
2347 widget *wid = NULL;
2348
2352 if (strcmp(name, "mainbox") == 0) {
2353 wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);
2354 box_add((box *)parent_widget, WIDGET(wid), TRUE);
2355 if (config.sidebar_mode) {
2356 defaults = "inputbar,message,listview,mode-switcher";
2357 } else {
2358 defaults = "inputbar,message,listview";
2359 }
2360 }
2364 else if (strcmp(name, "inputbar") == 0) {
2365 wid =
2366 (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);
2367 defaults = "prompt,entry,overlay,case-indicator";
2368 box_add((box *)parent_widget, WIDGET(wid), FALSE);
2369 }
2373 else if (strcmp(name, "prompt") == 0) {
2374 if (state->prompt != NULL) {
2375 g_error("Prompt widget can only be added once to the layout.");
2376 return;
2377 }
2378 // Prompt box.
2379 state->prompt =
2380 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2381 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
2383 box_add((box *)parent_widget, WIDGET(state->prompt), FALSE);
2384 defaults = NULL;
2385 } else if (strcmp(name, "num-rows") == 0) {
2386 state->tb_total_rows =
2387 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2388 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
2389 box_add((box *)parent_widget, WIDGET(state->tb_total_rows), FALSE);
2390 defaults = NULL;
2391 } else if (strcmp(name, "num-filtered-rows") == 0) {
2392 state->tb_filtered_rows =
2393 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2394 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
2395 box_add((box *)parent_widget, WIDGET(state->tb_filtered_rows), FALSE);
2396 defaults = NULL;
2397 } else if (strcmp(name, "textbox-current-entry") == 0) {
2398 state->tb_current_entry =
2399 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2400 TB_MARKUP | TB_AUTOHEIGHT, NORMAL, "", 0, 0);
2401 box_add((box *)parent_widget, WIDGET(state->tb_current_entry), FALSE);
2402 defaults = NULL;
2403 } else if (strcmp(name, "icon-current-entry") == 0) {
2404 state->icon_current_entry = icon_create(parent_widget, name);
2405 box_add((box *)parent_widget, WIDGET(state->icon_current_entry), FALSE);
2406 defaults = NULL;
2407 }
2411 else if (strcmp(name, "case-indicator") == 0) {
2412 if (state->case_indicator != NULL) {
2413 g_error("Case indicator widget can only be added once to the layout.");
2414 return;
2415 }
2416 state->case_indicator =
2417 textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2418 TB_AUTOWIDTH | TB_AUTOHEIGHT, NORMAL, "*", 0, 0);
2419 // Add small separator between case indicator and text box.
2420 box_add((box *)parent_widget, WIDGET(state->case_indicator), FALSE);
2422 }
2426 else if (strcmp(name, "entry") == 0) {
2427 if (state->text != NULL) {
2428 g_error("Entry textbox widget can only be added once to the layout.");
2429 return;
2430 }
2431 // Entry box
2433 tfl |= ((state->menu_flags & MENU_PASSWORD) == MENU_PASSWORD) ? TB_PASSWORD
2434 : 0;
2435 state->text = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,
2436 tfl | TB_AUTOHEIGHT, NORMAL, NULL, 0, 0);
2437 box_add((box *)parent_widget, WIDGET(state->text), TRUE);
2438 }
2442 else if (strcmp(name, "message") == 0) {
2443 if (state->mesg_box != NULL) {
2444 g_error("Message widget can only be added once to the layout.");
2445 return;
2446 }
2447 state->mesg_box = container_create(parent_widget, name);
2448 state->mesg_tb = textbox_create(
2449 WIDGET(state->mesg_box), WIDGET_TYPE_TEXTBOX_TEXT, "textbox",
2450 TB_AUTOHEIGHT | TB_MARKUP | TB_WRAP, NORMAL, NULL, 0, 0);
2451 container_add(state->mesg_box, WIDGET(state->mesg_tb));
2453 box_add((box *)parent_widget, WIDGET(state->mesg_box), FALSE);
2454 }
2458 else if (strcmp(name, "listview") == 0) {
2459 if (state->list_view != NULL) {
2460 g_error("Listview widget can only be added once to the layout.");
2461 return;
2462 }
2463 state->list_view =
2464 listview_create(parent_widget, name, update_callback,
2465 page_changed_callback, state, config.element_height, 0);
2467 state->list_view, selection_changed_callback, (void *)state);
2468 box_add((box *)parent_widget, WIDGET(state->list_view), TRUE);
2469 listview_set_scroll_type(state->list_view, config.scroll_method);
2471 state->list_view, rofi_view_listview_mouse_activated_cb, state);
2472
2473 listview_set_max_lines(state->list_view, state->num_lines);
2474 }
2478 else if (strcmp(name, "mode-switcher") == 0 || strcmp(name, "sidebar") == 0) {
2479 if (state->sidebar_bar != NULL) {
2480 g_error("Mode-switcher can only be added once to the layout.");
2481 return;
2482 }
2483 state->sidebar_bar =
2484 box_create(parent_widget, name, ROFI_ORIENTATION_HORIZONTAL);
2485 box_add((box *)parent_widget, WIDGET(state->sidebar_bar), FALSE);
2487 state->modes = g_malloc0(state->num_modes * sizeof(textbox *));
2488 for (unsigned int j = 0; j < state->num_modes; j++) {
2489 const Mode *mode = rofi_get_mode(j);
2490 state->modes[j] = textbox_create(
2491 WIDGET(state->sidebar_bar), WIDGET_TYPE_MODE_SWITCHER, "button",
2492 TB_AUTOHEIGHT, (mode == state->sw) ? HIGHLIGHT : NORMAL,
2493 mode_get_display_name(mode), 0.5, 0.5);
2494 box_add(state->sidebar_bar, WIDGET(state->modes[j]), TRUE);
2497 }
2498 } else if (g_ascii_strcasecmp(name, "overlay") == 0) {
2499 state->overlay = textbox_create(
2500 WIDGET(parent_widget), WIDGET_TYPE_TEXTBOX_TEXT, "overlay",
2501 TB_AUTOWIDTH | TB_AUTOHEIGHT, URGENT, "blaat", 0.5, 0);
2502 box_add((box *)parent_widget, WIDGET(state->overlay), FALSE);
2503 widget_disable(WIDGET(state->overlay));
2504 } else if (g_ascii_strncasecmp(name, "textbox", 7) == 0) {
2505 textbox *t = textbox_create(parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name,
2506 TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0);
2507 box_add((box *)parent_widget, WIDGET(t), TRUE);
2508 } else if (g_ascii_strncasecmp(name, "button", 6) == 0) {
2509 textbox *t = textbox_create(parent_widget, WIDGET_TYPE_EDITBOX, name,
2510 TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0);
2511 box_add((box *)parent_widget, WIDGET(t), TRUE);
2513 state);
2514 } else if (g_ascii_strncasecmp(name, "icon", 4) == 0) {
2515 icon *t = icon_create(parent_widget, name);
2516 /* small hack to make it clickable */
2517 const char *type = rofi_theme_get_string(WIDGET(t), "action", NULL);
2518 if (type) {
2519 WIDGET(t)->type = WIDGET_TYPE_EDITBOX;
2520 }
2521 box_add((box *)parent_widget, WIDGET(t), TRUE);
2523 state);
2524 } else {
2525 wid = (widget *)box_create(parent_widget, name, ROFI_ORIENTATION_VERTICAL);
2526 box_add((box *)parent_widget, WIDGET(wid), TRUE);
2527 // g_error("The widget %s does not exists. Invalid layout.", name);
2528 }
2529 if (wid) {
2530 GList *list = rofi_theme_get_list_strings(wid, "children");
2531 if (list == NULL) {
2532 if (defaults) {
2533 char **a = g_strsplit(defaults, ",", 0);
2534 for (int i = 0; a && a[i]; i++) {
2535 rofi_view_add_widget(state, wid, a[i]);
2536 }
2537 g_strfreev(a);
2538 }
2539 } else {
2540 for (const GList *iter = g_list_first(list); iter != NULL;
2541 iter = g_list_next(iter)) {
2542 rofi_view_add_widget(state, wid, (const char *)iter->data);
2543 }
2544 g_list_free_full(list, g_free);
2545 }
2546 }
2547}
2548
2550 xcb_query_pointer_cookie_t pointer_cookie =
2551 xcb_query_pointer(xcb->connection, CacheState.main_window);
2552 xcb_query_pointer_reply_t *pointer_reply =
2553 xcb_query_pointer_reply(xcb->connection, pointer_cookie, NULL);
2554
2555 if (pointer_reply == NULL) {
2556 return;
2557 }
2558
2559 rofi_view_handle_mouse_motion(state, pointer_reply->win_x,
2560 pointer_reply->win_y, config.hover_select);
2561
2562 free(pointer_reply);
2563}
2564
2565RofiViewState *rofi_view_create(Mode *sw, const char *input,
2566 MenuFlags menu_flags,
2567 void (*finalize)(RofiViewState *)) {
2568 TICK();
2570 state->menu_flags = menu_flags;
2571 state->sw = sw;
2572 state->selected_line = UINT32_MAX;
2573 state->previous_line = UINT32_MAX;
2574 state->retv = MENU_CANCEL;
2575 state->distance = NULL;
2576 state->quit = FALSE;
2577 state->skip_absorb = FALSE;
2578 // We want to filter on the first run.
2579 state->refilter = TRUE;
2580 state->finalize = finalize;
2581 state->mouse_seen = FALSE;
2582
2583 // In password mode, disable the entry history.
2584 if ((menu_flags & MENU_PASSWORD) == MENU_PASSWORD) {
2585 CacheState.entry_history_enable = FALSE;
2586 g_debug("Disable entry history, because password setup.");
2587 }
2588 if (config.disable_history) {
2589 CacheState.entry_history_enable = FALSE;
2590 g_debug("Disable entry history, because history disable flag.");
2591 }
2592 // Request the lines to show.
2593 state->num_lines = mode_get_num_entries(sw);
2594
2595 if (state->sw) {
2596 char *title =
2597 g_strdup_printf("rofi - %s", mode_get_display_name(state->sw));
2599 g_free(title);
2600 } else {
2602 }
2603 TICK_N("Startup notification");
2604
2605 // Get active monitor size.
2606 TICK_N("Get active monitor");
2607
2608 state->main_window = box_create(NULL, "window", ROFI_ORIENTATION_VERTICAL);
2609 // Get children.
2610 GList *list =
2611 rofi_theme_get_list_strings(WIDGET(state->main_window), "children");
2612 if (list == NULL) {
2613 rofi_view_add_widget(state, WIDGET(state->main_window), "mainbox");
2614 } else {
2615 for (const GList *iter = list; iter != NULL; iter = g_list_next(iter)) {
2617 (const char *)iter->data);
2618 }
2619 g_list_free_full(list, g_free);
2620 }
2621
2622 if (state->text && input) {
2623 textbox_text(state->text, input);
2624 textbox_cursor_end(state->text);
2625 }
2626
2627 // filtered list
2628 state->line_map = g_malloc0_n(state->num_lines, sizeof(unsigned int));
2629 state->distance = (int *)g_malloc0_n(state->num_lines, sizeof(int));
2630
2632 // Only needed when window is fixed size.
2635 }
2636
2637 state->height = rofi_view_calculate_height(state);
2638 // Move the window to the correct x,y position.
2641
2642 state->quit = FALSE;
2643 rofi_view_refilter(state);
2644 rofi_view_update(state, TRUE);
2645 xcb_map_window(xcb->connection, CacheState.main_window);
2647 rofi_view_ping_mouse(state);
2648 xcb_flush(xcb->connection);
2649
2651 /* When Override Redirect, the WM will not let us know we can take focus, so
2652 * just steal it */
2653 if (((menu_flags & MENU_NORMAL_WINDOW) == 0)) {
2655 }
2656
2657 if (xcb->sncontext != NULL) {
2658 sn_launchee_context_complete(xcb->sncontext);
2659 }
2660 return state;
2661}
2662
2663static void rofi_error_user_callback(const char *msg) {
2664 if (config.on_menu_error == NULL)
2665 return;
2666
2667 char **args = NULL;
2668 int argv = 0;
2669 helper_parse_setup(config.on_menu_error, &args, &argv, "{error}", msg,
2670 (char *)0);
2671 if (args != NULL)
2672 helper_execute(NULL, args, "", config.on_menu_error, NULL);
2673}
2674
2675int rofi_view_error_dialog(const char *msg, int markup) {
2677 state->retv = MENU_CANCEL;
2679 state->finalize = process_result;
2680
2681 state->main_window = box_create(NULL, "window", ROFI_ORIENTATION_VERTICAL);
2682 box *new_box = box_create(WIDGET(state->main_window), "error-message",
2684 box_add(state->main_window, WIDGET(new_box), TRUE);
2685 state->text =
2686 textbox_create(WIDGET(new_box), WIDGET_TYPE_TEXTBOX_TEXT, "textbox",
2687 (TB_AUTOHEIGHT | TB_WRAP) + ((markup) ? TB_MARKUP : 0),
2688 NORMAL, (msg != NULL) ? msg : "", 0, 0);
2689 box_add(new_box, WIDGET(state->text), TRUE);
2690
2691 // Make sure we enable fixed num lines when in normal window mode.
2694 }
2696 state->height = rofi_view_calculate_height(state);
2697
2698 // Calculate window position.
2700
2701 // Move the window to the correct x,y position.
2703
2704 // Display it.
2705 xcb_map_window(xcb->connection, CacheState.main_window);
2707
2708 if (xcb->sncontext != NULL) {
2709 sn_launchee_context_complete(xcb->sncontext);
2710 }
2711
2712 // Exec custom command
2714
2715 // Set it as current window.
2716 rofi_view_set_active(state);
2717 return TRUE;
2718}
2719
2720void rofi_view_hide(void) {
2721 if (CacheState.main_window != XCB_WINDOW_NONE) {
2723 xcb_unmap_window(xcb->connection, CacheState.main_window);
2725 }
2726}
2727
2729 // Clear clipboard data.
2731 g_debug("Cleanup.");
2732 if (CacheState.idle_timeout > 0) {
2733 g_source_remove(CacheState.idle_timeout);
2734 CacheState.idle_timeout = 0;
2735 }
2736 if (CacheState.refilter_timeout > 0) {
2737 g_source_remove(CacheState.refilter_timeout);
2738 CacheState.refilter_timeout = 0;
2739 }
2740 if (CacheState.overlay_timeout) {
2741 g_source_remove(CacheState.overlay_timeout);
2742 CacheState.overlay_timeout = 0;
2743 }
2744 if (CacheState.user_timeout > 0) {
2745 g_source_remove(CacheState.user_timeout);
2746 CacheState.user_timeout = 0;
2747 }
2748 if (CacheState.repaint_source > 0) {
2749 g_source_remove(CacheState.repaint_source);
2750 CacheState.repaint_source = 0;
2751 }
2752 if (CacheState.fake_bg) {
2753 cairo_surface_destroy(CacheState.fake_bg);
2754 CacheState.fake_bg = NULL;
2755 }
2756 if (CacheState.edit_draw) {
2757 cairo_destroy(CacheState.edit_draw);
2758 CacheState.edit_draw = NULL;
2759 }
2760 if (CacheState.edit_surf) {
2761 cairo_surface_destroy(CacheState.edit_surf);
2762 CacheState.edit_surf = NULL;
2763 }
2764 if (CacheState.main_window != XCB_WINDOW_NONE) {
2765 g_debug("Unmapping and free'ing window");
2766 xcb_unmap_window(xcb->connection, CacheState.main_window);
2768 xcb_free_gc(xcb->connection, CacheState.gc);
2769 xcb_free_pixmap(xcb->connection, CacheState.edit_pixmap);
2770 xcb_destroy_window(xcb->connection, CacheState.main_window);
2771 CacheState.main_window = XCB_WINDOW_NONE;
2772 }
2773 if (map != XCB_COLORMAP_NONE) {
2774 xcb_free_colormap(xcb->connection, map);
2775 map = XCB_COLORMAP_NONE;
2776 }
2777 xcb_flush(xcb->connection);
2778 g_assert(g_queue_is_empty(&(CacheState.views)));
2779
2781}
2782
2783static int rofi_thread_workers_sort(gconstpointer a, gconstpointer b,
2784 gpointer data G_GNUC_UNUSED) {
2785 thread_state *tsa = (thread_state *)a;
2786 thread_state *tsb = (thread_state *)b;
2787 // lower number is lower priority.. a is sorted above is a > b.
2788 return tsa->priority - tsb->priority;
2789}
2790
2791static void rofi_thread_pool_state_free(gpointer data) {
2792 if (data) {
2793 // This is a weirdness from glib that should not happen.
2794 // It pushes in a 1 to msg sleeping threads to wake up.
2795 // This should be removed from queue to avoid hitting this method.
2796 // In practice, we still hit it (and crash)
2797 if (GPOINTER_TO_UINT(data) == 1) {
2798 // Ignore this entry.
2799 g_debug("Glib thread-pool bug, received pointer with value 1.");
2800 return;
2801 }
2802 thread_state *ts = (thread_state *)data;
2803 if (ts->free) {
2804 ts->free(data);
2805 }
2806 }
2807}
2808
2810 TICK_N("Setup Threadpool, start");
2811 if (config.threads == 0) {
2812 config.threads = 1;
2813 long procs = sysconf(_SC_NPROCESSORS_CONF);
2814 if (procs > 0) {
2815 config.threads = MIN(procs, 128l);
2816 }
2817 }
2818 // Create thread pool
2819 GError *error = NULL;
2820 tpool = g_thread_pool_new_full(rofi_view_call_thread, NULL,
2822 FALSE, &error);
2823 if (error == NULL) {
2824 // Idle threads should stick around for a max of 60 seconds.
2825 g_thread_pool_set_max_idle_time(60000);
2826 // We are allowed to have
2827 g_thread_pool_set_max_threads(tpool, config.threads, &error);
2828 }
2829 // If error occurred during setup of pool, tell user and exit.
2830 if (error != NULL) {
2831 g_warning("Failed to setup thread pool: '%s'", error->message);
2832 g_error_free(error);
2833 exit(EXIT_FAILURE);
2834 }
2835 g_thread_pool_set_sort_function(tpool, rofi_thread_workers_sort, NULL);
2836 TICK_N("Setup Threadpool, done");
2837}
2839 if (tpool) {
2840 // Discard all unprocessed jobs and don't wait for current jobs in execution
2841 g_thread_pool_free(tpool, TRUE, FALSE);
2842 tpool = NULL;
2843 }
2844}
2845Mode *rofi_view_get_mode(RofiViewState *state) { return state->sw; }
2846
2847static gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data) {
2849 if (state) {
2850 widget_disable(WIDGET(state->overlay));
2851 }
2852 CacheState.overlay_timeout = 0;
2854 return G_SOURCE_REMOVE;
2855}
2856
2857void rofi_view_set_overlay_timeout(RofiViewState *state, const char *text) {
2858 if (state->overlay == NULL || state->list_view == NULL) {
2859 return;
2860 }
2861 if (text == NULL) {
2862 widget_disable(WIDGET(state->overlay));
2863 return;
2864 }
2865 rofi_view_set_overlay(state, text);
2866 int timeout = rofi_theme_get_integer(WIDGET(state->overlay), "timeout", 3);
2867 CacheState.overlay_timeout =
2868 g_timeout_add_seconds(timeout, rofi_view_overlay_timeout, state);
2869}
2870
2871void rofi_view_set_overlay(RofiViewState *state, const char *text) {
2872 if (state->overlay == NULL || state->list_view == NULL) {
2873 return;
2874 }
2875 if (CacheState.overlay_timeout > 0) {
2876 g_source_remove(CacheState.overlay_timeout);
2877 CacheState.overlay_timeout = 0;
2878 }
2879 if (text == NULL) {
2880 widget_disable(WIDGET(state->overlay));
2881 return;
2882 }
2883 widget_enable(WIDGET(state->overlay));
2884 textbox_text(state->overlay, text);
2885 // We want to queue a repaint.
2887}
2888
2890 if (state->text) {
2891 textbox_text(state->text, "");
2893 }
2894}
2895
2897 PangoEllipsizeMode mode) {
2898 listview_set_ellipsize(state->list_view, mode);
2899}
2900
2902 state->sw = mode;
2903 // Update prompt;
2904 if (state->prompt) {
2906 }
2907 if (state->sw) {
2908 char *title =
2909 g_strdup_printf("rofi - %s", mode_get_display_name(state->sw));
2911 g_free(title);
2912 } else {
2914 }
2915 if (state->sidebar_bar) {
2916 for (unsigned int j = 0; j < state->num_modes; j++) {
2917 const Mode *tb_mode = rofi_get_mode(j);
2918 textbox_font(state->modes[j],
2919 (tb_mode == state->sw) ? HIGHLIGHT : NORMAL);
2920 }
2921 }
2922 rofi_view_restart(state);
2923 state->reload = TRUE;
2924 state->refilter = TRUE;
2926 rofi_view_update(state, TRUE);
2927}
2928
2929xcb_window_t rofi_view_get_window(void) { return CacheState.main_window; }
2930
2931void rofi_view_set_window_title(const char *title) {
2932 ssize_t len = strlen(title);
2933 xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,
2934 CacheState.main_window, xcb->ewmh._NET_WM_NAME,
2935 xcb->ewmh.UTF8_STRING, 8, len, title);
2936 xcb_change_property(xcb->connection, XCB_PROP_MODE_REPLACE,
2937 CacheState.main_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING,
2938 8, len, title);
2939}
@ WL_SOUTH_EAST
Definition rofi-types.h:249
@ WL_CENTER
Definition rofi-types.h:235
@ WL_NORTH_WEST
Definition rofi-types.h:245
@ WL_SOUTH
Definition rofi-types.h:241
@ WL_NORTH_EAST
Definition rofi-types.h:247
@ WL_WEST
Definition rofi-types.h:243
@ WL_NORTH
Definition rofi-types.h:237
@ WL_EAST
Definition rofi-types.h:239
@ WL_SOUTH_WEST
Definition rofi-types.h:251
PangoAttrList * helper_token_match_get_pango_attr(RofiHighlightColorStyle th, rofi_int_matcher **tokens, const char *input, PangoAttrList *retv)
Definition helper.c:511
gboolean helper_validate_font(PangoFontDescription *pfd, const char *font)
Definition helper.c:653
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
Definition helper.c:287
unsigned int levenshtein(const char *needle, const glong needlelen, const char *haystack, const glong haystacklen, int case_sensitive)
Definition helper.c:813
Property * rofi_theme_find_property(ThemeWidget *wid, PropertyType type, const char *property, gboolean exact)
Definition theme.c:743
gboolean helper_execute_command(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context)
Definition helper.c:1071
void helper_select_next_matching_mode(void)
Definition helper.c:84
void helper_tokenize_free(rofi_int_matcher **tokens)
Definition helper.c:147
const char * helper_get_matching_mode_str(void)
Definition helper.c:81
gboolean helper_execute(const char *wd, char **args, const char *error_precmd, const char *error_cmd, RofiHelperExecuteContext *context)
Definition helper.c:1043
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
Definition theme.c:780
int helper_parse_setup(char *string, char ***output, int *length,...)
Definition helper.c:103
#define rofi_fallthrough
Definition helper.h:466
void helper_select_previous_matching_mode(void)
Definition helper.c:90
char * rofi_expand_path(const char *input)
Definition helper.c:781
int parse_case_sensitivity(const char *input)
Definition helper.c:1294
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str, glong slen, int case_sensitive)
Definition helper.c:962
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:150
void rofi_quit_main_loop(void)
Definition rofi.c:736
#define color_reset
Definition rofi.h:115
unsigned int rofi_get_num_enabled_modes(void)
Definition rofi.c:148
const char * cache_dir
Definition rofi.c:80
#define color_green
Definition rofi.h:121
#define TICK()
Definition timings.h:64
#define TICK_N(a)
Definition timings.h:69
void textbox_font(textbox *tb, TextBoxFontType tbft)
Definition textbox.c:308
TextboxFlags
Definition textbox.h:93
int textbox_keybinding(textbox *tb, KeyBindingAction action)
Definition textbox.c:865
TextBoxFontType
Definition textbox.h:104
void textbox_set_pango_attributes(textbox *tb, PangoAttrList *list)
Definition textbox.c:384
const char * textbox_get_visible_text(const textbox *tb)
Definition textbox.c:372
int textbox_get_cursor(const textbox *tb)
Definition textbox.c:397
void textbox_cursor(textbox *tb, int pos)
Definition textbox.c:637
void textbox_set_pango_context(const char *font, PangoContext *p)
Definition textbox.c:974
textbox * textbox_create(widget *parent, WidgetType type, const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text, double xalign, double yalign)
Definition textbox.c:204
void textbox_cursor_end(textbox *tb)
Definition textbox.c:739
gboolean textbox_append_text(textbox *tb, const char *pad, const int pad_len)
Definition textbox.c:927
PangoAttrList * textbox_get_pango_attributes(textbox *tb)
Definition textbox.c:378
void textbox_text(textbox *tb, const char *text)
Definition textbox.c:404
int textbox_get_cursor_x_pos(const textbox *tb)
Definition textbox.c:1100
char * textbox_get_text(const textbox *tb)
Definition textbox.c:391
@ TB_AUTOHEIGHT
Definition textbox.h:94
@ TB_PASSWORD
Definition textbox.h:99
@ TB_MARKUP
Definition textbox.h:97
@ TB_WRAP
Definition textbox.h:98
@ TB_EDITABLE
Definition textbox.h:96
@ TB_AUTOWIDTH
Definition textbox.h:95
@ URGENT
Definition textbox.h:108
@ HIGHLIGHT
Definition textbox.h:119
@ NORMAL
Definition textbox.h:106
void rofi_view_cleanup(void)
Definition view.c:2728
void rofi_view_set_overlay(RofiViewState *state, const char *text)
Definition view.c:2871
void __create_window(MenuFlags menu_flags)
Definition view.c:1022
void rofi_view_clear_input(RofiViewState *state)
Definition view.c:2889
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Definition view.c:2901
Mode * rofi_view_get_mode(RofiViewState *state)
Definition view.c:2845
void rofi_view_hide(void)
Definition view.c:2720
void rofi_view_reload(void)
Definition view.c:602
xcb_window_t rofi_view_get_window(void)
Definition view.c:2929
void rofi_view_remove_active(RofiViewState *state)
Definition view.c:625
void rofi_view_set_overlay_timeout(RofiViewState *state, const char *text)
Definition view.c:2857
int rofi_view_error_dialog(const char *msg, int markup)
Definition view.c:2675
void rofi_view_set_active(RofiViewState *state)
Definition view.c:632
void rofi_view_queue_redraw(void)
Definition view.c:609
RofiViewState * rofi_view_get_active(void)
Definition view.c:623
void rofi_view_restart(RofiViewState *state)
Definition view.c:618
MenuFlags
Definition view.h:50
void rofi_view_handle_text(RofiViewState *state, char *text)
Definition view.c:2074
void rofi_view_trigger_action(RofiViewState *state, BindingsScope scope, guint action)
Definition view.c:2033
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition view.c:692
unsigned int rofi_view_get_completed(const RofiViewState *state)
Definition view.c:709
gboolean rofi_view_check_action(RofiViewState *state, BindingsScope scope, guint action)
Definition view.c:2002
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition view.c:713
void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y, gboolean find_mouse_target)
Definition view.c:2116
void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target)
Definition view.c:2238
void rofi_view_finalize(RofiViewState *state)
Definition view.c:1656
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition view.c:655
void rofi_view_temp_configure_notify(RofiViewState *state, xcb_configure_notify_event_t *xce)
Definition view.c:2204
void rofi_view_frame_callback(void)
Definition view.c:2247
void rofi_view_free(RofiViewState *state)
Definition view.c:674
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition view.c:2565
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
Definition view.c:696
unsigned int rofi_view_get_next_position(const RofiViewState *state)
Definition view.c:700
void rofi_view_maybe_update(RofiViewState *state)
Definition view.c:2175
@ MENU_PASSWORD
Definition view.h:54
@ MENU_TRANSIENT_WINDOW
Definition view.h:60
@ MENU_NORMAL_WINDOW
Definition view.h:56
@ MENU_ERROR_DIALOG
Definition view.h:58
@ MENU_NORMAL
Definition view.h:52
gboolean rofi_set_im_window_pos(int new_x, int new_y)
void rofi_capture_screenshot(void)
Definition view.c:233
void rofi_view_workers_initialize(void)
Definition view.c:2809
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:2273
void rofi_view_set_window_title(const char *title)
Definition view.c:2931
void rofi_view_ellipsize_listview(RofiViewState *state, PangoEllipsizeMode mode)
Definition view.c:2896
void rofi_view_get_current_monitor(int *width, int *height)
Definition view.c:186
void rofi_view_workers_finalize(void)
Definition view.c:2838
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:178
void widget_free(widget *wid)
Definition widget.c:425
void widget_draw(widget *wid, cairo_t *d)
Definition widget.c:140
int widget_get_height(widget *wid)
Definition widget.c:437
struct _widget widget
Definition widget.h:51
int widget_get_y_pos(widget *wid)
Definition widget.c:461
WidgetType
Definition widget.h:56
int widget_get_x_pos(widget *wid)
Definition widget.c:455
void widget_resize(widget *wid, short w, short h)
Definition widget.c:92
#define WIDGET(a)
Definition widget.h:119
static void widget_disable(widget *wid)
Definition widget.h:170
WidgetTriggerActionResult
Definition widget.h:76
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
gboolean widget_need_redraw(widget *wid)
Definition widget.c:500
widget * widget_find_mouse_target(widget *wid, WidgetType type, gint x, gint y)
Definition widget.c:510
@ WIDGET_TYPE_UNKNOWN
Definition widget.h:58
@ WIDGET_TYPE_LISTVIEW_ELEMENT
Definition widget.h:62
@ WIDGET_TYPE_TEXTBOX_TEXT
Definition widget.h:70
@ WIDGET_TYPE_MODE_SWITCHER
Definition widget.h:68
@ WIDGET_TYPE_EDITBOX
Definition widget.h:64
@ WIDGET_TRIGGER_ACTION_RESULT_HANDLED
Definition widget.h:80
@ WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_END
Definition widget.h:84
@ WIDGET_TRIGGER_ACTION_RESULT_GRAB_MOTION_BEGIN
Definition widget.h:82
@ WIDGET_TRIGGER_ACTION_RESULT_IGNORED
Definition widget.h:78
@ 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:88
void process_result(RofiViewState *state)
Definition rofi.c:233
Settings config
#define DEFAULT_MENU_WIDTH
Definition settings.h:218
@ SORT_FZF
Definition settings.h:50
@ SORT_NORMAL
Definition settings.h:50
char * string
Definition view.c:105
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
listview * list_view
struct RofiViewState::@141050056035150177024355252222311351137250305333 mouse
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:753
unsigned int count
Definition view.c:750
GMutex * mutex
Definition view.c:739
unsigned int stop
Definition view.c:748
thread_state st
Definition view.c:734
RofiViewState * state
Definition view.c:744
unsigned int * acount
Definition view.c:741
unsigned int start
Definition view.c:746
GCond * cond
Definition view.c:737
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:65
widget widget
Definition textbox.h:62
int rofi_theme_get_integer(const widget *wid, const char *property, int def)
Definition theme.c:840
RofiHighlightColorStyle rofi_theme_get_highlight(widget *wid, const char *property, RofiHighlightColorStyle th)
Definition theme.c:1309
int rofi_theme_get_position(const widget *wid, const char *property, int def)
Definition theme.c:816
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
Definition theme.c:1405
int rofi_theme_get_boolean(const widget *wid, const char *property, int def)
Definition theme.c:901
RofiDistance rofi_theme_get_distance(const widget *wid, const char *property, int def)
Definition theme.c:875
GList * rofi_theme_get_list_strings(const widget *wid, const char *property)
Definition theme.c:1259
const char * rofi_theme_get_string(const widget *wid, const char *property, const char *def)
Definition theme.c:987
static void rofi_view_call_thread(gpointer data, gpointer user_data)
Definition view.c:763
cairo_surface_t * fake_bg
Definition view.c:115
static void rofi_view_nav_last(RofiViewState *state)
Definition view.c:1298
struct @303212127125276242164050310102020023110254275240 CacheState
static gboolean rofi_view_repaint(G_GNUC_UNUSED void *data)
Definition view.c:339
static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data)
Definition view.c:575
static gboolean rofi_view_reload_idle(G_GNUC_UNUSED gpointer data)
Definition view.c:536
static gboolean bench_update(void)
Definition view.c:315
static void rofi_error_user_callback(const char *msg)
Definition view.c:2663
static char * get_matching_state(RofiViewState *state)
Definition view.c:194
struct _thread_state_view thread_state_view
guint idle_timeout
Definition view.c:133
guint refilter_timeout_count
Definition view.c:137
static void rofi_view_nav_row_select(RofiViewState *state)
Definition view.c:1268
GQueue views
Definition view.c:129
static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom, void *udata)
Definition view.c:2331
EntryHistoryIndex * entry_history
Definition view.c:159
static gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data)
Definition view.c:2847
static void screenshot_taken_user_callback(const char *path)
Definition view.c:218
GTimer * time
Definition view.c:306
cairo_surface_t * edit_surf
Definition view.c:121
static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget, const char *name)
Definition view.c:2344
static void update_callback(textbox *t, icon *ico, unsigned int index, void *udata, TextBoxFontType *type, gboolean full)
Definition view.c:1355
static void rofi_view_nav_row_tab(RofiViewState *state)
Definition view.c:1244
static void rofi_view_setup_fake_transparency(widget *win, const char *const fake_background)
Definition view.c:805
static void input_history_save(void)
Definition view.c:981
gboolean entry_history_enable
Definition view.c:157
static void rofi_view_reload_message_bar(RofiViewState *state)
Definition view.c:499
static void rofi_view_nav_first(RofiViewState *state)
Definition view.c:1288
xcb_window_t main_window
Definition view.c:113
static gboolean rofi_view_refilter_real(RofiViewState *state)
Definition view.c:1469
xcb_gcontext_t gc
Definition view.c:117
guint user_timeout
Definition view.c:145
cairo_t * edit_draw
Definition view.c:123
gboolean delayed_mode
Definition view.c:143
static void page_changed_callback(void)
Definition view.c:1410
void rofi_view_update(RofiViewState *state, gboolean qr)
Definition view.c:1415
guint refilter_timeout
Definition view.c:135
static const int loc_transtable[9]
Definition view.c:378
xcb_pixmap_t edit_pixmap
Definition view.c:119
static RofiViewState * __rofi_view_state_create(void)
Definition view.c:725
static void rofi_view_trigger_global_action(KeyBindingAction action)
Definition view.c:1682
workarea mon
Definition view.c:131
static void rofi_view_input_changed(void)
Definition view.c:1666
gssize entry_history_index
Definition view.c:163
double max_refilter_time
Definition view.c:141
int fake_bgrel
Definition view.c:125
static void filter_elements(thread_state *ts, G_GNUC_UNUSED gpointer user_data)
Definition view.c:768
void process_result(RofiViewState *state)
Definition rofi.c:233
static void rofi_view_update_prompt(RofiViewState *state)
Definition view.c:359
static struct @224217335044137010276353040043060036143107331103 BenchMark
static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data)
Definition view.c:569
static void rofi_view_refilter(RofiViewState *state)
Definition view.c:1611
X11CursorType cursor_type
Definition view.c:155
static int rofi_view_calculate_height(RofiViewState *state)
Definition view.c:2256
GThreadPool * tpool
Definition view.c:99
double min
Definition view.c:312
RofiViewState * current_active_menu
Definition view.c:102
static void rofi_thread_pool_state_free(gpointer data)
Definition view.c:2791
gssize entry_history_length
Definition view.c:161
MenuFlags flags
Definition view.c:127
unsigned long long count
Definition view.c:149
static int rofi_thread_workers_sort(gconstpointer a, gconstpointer b, gpointer data G_GNUC_UNUSED)
Definition view.c:2783
static void rofi_view_calculate_window_position(RofiViewState *state)
Definition view.c:382
uint64_t draws
Definition view.c:308
double last_ts
Definition view.c:310
static void rofi_view_set_cursor(RofiCursorType type)
Definition view.c:2104
static void selection_changed_user_callback(unsigned int index, RofiViewState *state)
Definition view.c:1306
static void rofi_view_take_action(const char *name)
Definition view.c:553
static void selection_changed_callback(G_GNUC_UNUSED listview *lv, unsigned int index, void *udata)
Definition view.c:1322
static void rofi_quit_user_callback(RofiViewState *state)
Definition view.c:2144
static void rofi_view_ping_mouse(RofiViewState *state)
Definition view.c:2549
static void rofi_view_window_update_size(RofiViewState *state)
Definition view.c:469
gboolean fullscreen
Definition view.c:153
static void rofi_view_calculate_window_width(RofiViewState *state)
Definition view.c:1222
static X11CursorType rofi_cursor_type_to_x11_cursor_type(RofiCursorType type)
Definition view.c:2081
static RofiCursorType rofi_view_resolve_cursor(RofiViewState *state, gint x, gint y)
Definition view.c:2096
static int lev_sort(const void *p1, const void *p2, void *arg)
Definition view.c:210
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:2302
guint overlay_timeout
Definition view.c:147
static void _rofi_view_reload_row(RofiViewState *state)
Definition view.c:1459
guint repaint_source
Definition view.c:151
static void input_history_initialize(void)
Definition view.c:938
static void rofi_view_refilter_force(RofiViewState *state)
Definition view.c:1641
xcb_colormap_t map
Definition xcb.c:108
int monitor_active(workarea *mon)
Definition xcb.c:1003
void display_early_cleanup(void)
Definition xcb.c:1951
cairo_surface_t * x11_helper_get_screenshot_surface(void)
Definition xcb.c:346
xcb_stuff * xcb
Definition xcb.c:101
xcb_depth_t * depth
Definition xcb.c:106
void rofi_xcb_revert_input_focus(void)
Definition xcb.c:1516
cairo_surface_t * x11_helper_get_bg_surface(void)
Definition xcb.c:372
void rofi_xcb_set_input_focus(xcb_window_t w)
Definition xcb.c:1493
void x11_set_cursor(xcb_window_t window, X11CursorType type)
Definition xcb.c:2015
void cairo_image_surface_blur(cairo_surface_t *surface, int radius, double deviation)
Definition xcb.c:176
xcb_window_t xcb_stuff_get_root_window(void)
Definition xcb.c:1949
void window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count)
Definition xcb.c:412
void xcb_stuff_set_clipboard(char *data)
Definition xcb.c:2027
void x11_disable_decoration(xcb_window_t window)
Definition xcb.c:1991
xcb_atom_t netatoms[NUM_NETATOMS]
Definition xcb.c:113
xcb_visualtype_t * visual
Definition xcb.c:107
struct _workarea workarea
X11CursorType
Definition xcb.h:184
@ CURSOR_POINTER
Definition xcb.h:188
@ CURSOR_DEFAULT
Definition xcb.h:186
@ CURSOR_TEXT
Definition xcb.h:190