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