29#define G_LOG_DOMAIN "View"
41#include <xcb-imdkit/encoding.h>
43#include <xcb/xcb_ewmh.h>
44#include <xcb/xcb_icccm.h>
46#include <xkbcommon/xkbcommon-x11.h>
53#define SN_API_NOT_YET_FROZEN
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};
164}
CacheState = {.main_window = XCB_WINDOW_NONE,
170 .views = G_QUEUE_INIT,
172 .refilter_timeout = 0,
173 .refilter_timeout_count = 0,
174 .max_refilter_time = 0.0,
175 .delayed_mode = FALSE,
177 .overlay_timeout = 0,
181 .entry_history_enable = TRUE,
182 .entry_history = NULL,
183 .entry_history_length = 0,
184 .entry_history_index = 0};
210static int lev_sort(
const void *p1,
const void *p2,
void *arg) {
213 int *distances = arg;
215 return distances[*a] - distances[*b];
219 if (
config.on_screenshot_taken == NULL)
236 g_warning(
"Nothing to screenshot.");
239 const char *outp = g_getenv(
"ROFI_PNG_OUTPUT");
240 const char *xdg_pict_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
241 if (outp == NULL && xdg_pict_dir == NULL) {
242 g_warning(
"XDG user picture directory or ROFI_PNG_OUTPUT is not set. "
243 "Cannot store screenshot.");
247 GDateTime *now = g_date_time_new_now_local();
249 char *timestmp = g_date_time_format(now,
"rofi-%Y-%m-%d-%H%M");
250 char *filename = g_strdup_printf(
"%s-%05d.png", timestmp, 0);
255 fpath = g_build_filename(xdg_pict_dir, filename, NULL);
256 while (g_file_test(fpath, G_FILE_TEST_EXISTS) && index < 99999) {
262 filename = g_strdup_printf(
"%s-%05d.png", timestmp, index);
264 fpath = g_build_filename(xdg_pict_dir, filename, NULL);
267 fpath = g_strdup(outp);
270 cairo_surface_t *surf = cairo_image_surface_create(
272 cairo_status_t status = cairo_surface_status(surf);
273 if (status != CAIRO_STATUS_SUCCESS) {
274 g_warning(
"Failed to produce screenshot '%s', got error: '%s'", fpath,
275 cairo_status_to_string(status));
277 cairo_t *draw = cairo_create(surf);
278 status = cairo_status(draw);
279 if (status != CAIRO_STATUS_SUCCESS) {
280 g_warning(
"Failed to produce screenshot '%s', got error: '%s'", fpath,
281 cairo_status_to_string(status));
284 status = cairo_surface_write_to_png(surf, fpath);
285 if (status != CAIRO_STATUS_SUCCESS) {
286 g_warning(
"Failed to produce screenshot '%s', got error: '%s'", fpath,
287 cairo_status_to_string(status));
294 cairo_surface_destroy(surf);
298 g_date_time_unref(now);
313}
BenchMark = {.time = NULL, .draws = 0, .last_ts = 0.0, .min = G_MAXDOUBLE};
316 if (!
config.benchmark_ui) {
325 double ts = g_timer_elapsed(
BenchMark.time, NULL);
326 double fps = 1024 / (ts -
BenchMark.last_ts);
331 printf(
"current: %.2f fps, avg: %.2f fps, min: %.2f fps, %lu draws\r\n",
347 g_debug(
"expose event");
352 xcb_flush(
xcb->connection);
356 return (
bench_update() == TRUE) ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
431 state->
x -= state->
width / 2;
444 state->
x -= state->
width / 2;
455 state->
x -= state->
width / 2;
462 "x-offset",
config.x_offset);
464 "y-offset",
config.y_offset);
473 uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
474 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
475 uint32_t vals[] = {state->
x, state->
y, state->
width, state->
height};
478 xcb_configure_window(
xcb->connection,
CacheState.main_window, mask, vals);
492 g_debug(
"Re-size window based internal request: %dx%d.", state->
width,
507 GString *emesg = g_string_new(msg);
510 g_string_append_c(emesg,
'\n');
513 emesg,
"The following warnings were detected when starting rofi:\n");
516 for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
517 GString *in_msg = (GString *)(iter->data);
518 g_string_append(emesg,
"\n\n");
519 g_string_append(emesg, in_msg->str);
522 if (g_list_length(iter) > 1) {
523 g_string_append_printf(emesg,
"\nThere are <b>%u</b> more errors.",
524 g_list_length(iter) - 1);
529 g_string_free(emesg, TRUE);
550 return G_SOURCE_REMOVE;
559 const char *action = p->
value.
s;
561 if (
id != UINT32_MAX) {
564 g_warning(
"Failed to parse keybinding: %s\r\n", action);
572 return G_SOURCE_REMOVE;
593 double delay = prop->
value.
f;
637 g_debug(
"stack view.");
642 if (state == NULL && !g_queue_is_empty(&(
CacheState.views))) {
643 g_debug(
"pop view.");
656 unsigned int selected_line) {
659 unsigned int selected = 0;
660 for (
unsigned int i = 0; ((state->
selected_line)) < UINT32_MAX && !selected &&
670 xcb_clear_area(
xcb->connection, 1,
CacheState.main_window, 0, 0, 1, 1);
671 xcb_flush(
xcb->connection);
687 g_free(state->
modes);
704 (next_pos) = state->
line_map[selected + 1];
769 G_GNUC_UNUSED gpointer user_data) {
771 for (
unsigned int i = t->
start; i < t->stop; i++) {
779 glong slen = g_utf8_strlen(str, -1);
780 switch (
config.sorting_method_enum) {
797 g_mutex_lock(t->
mutex);
799 g_cond_signal(t->
cond);
800 g_mutex_unlock(t->
mutex);
806 const char *
const fake_background) {
808 cairo_surface_t *s = NULL;
814 if (g_strcmp0(fake_background,
"real") == 0) {
817 if (g_strcmp0(fake_background,
"screenshot") == 0) {
819 }
else if (g_strcmp0(fake_background,
"background") == 0) {
823 g_debug(
"Opening %s to use as background.", fpath);
824 s = cairo_image_surface_create_from_png(fpath);
830 if (cairo_surface_status(s) != CAIRO_STATUS_SUCCESS) {
831 g_debug(
"Failed to open surface fake background: %s",
832 cairo_status_to_string(cairo_surface_status(s)));
833 cairo_surface_destroy(s);
836 CacheState.fake_bg = cairo_image_surface_create(
840 cairo_t *dr = cairo_create(
CacheState.fake_bg);
842 cairo_set_source_surface(dr, s, 0, 0);
848 cairo_surface_destroy(s);
855 TICK_N(
"Fake transparency");
860static void xim_commit_string(xcb_xim_t *im, G_GNUC_UNUSED xcb_xic_t ic,
861 G_GNUC_UNUSED uint32_t flag,
char *str,
862 uint32_t length, G_GNUC_UNUSED uint32_t *keysym,
863 G_GNUC_UNUSED
size_t nKeySym,
864 G_GNUC_UNUSED
void *user_data) {
870#ifndef XCB_IMDKIT_1_0_3_LOWER
871 if (xcb_xim_get_encoding(im) == XCB_XIM_UTF8_STRING) {
873 }
else if (xcb_xim_get_encoding(im) == XCB_XIM_COMPOUND_TEXT) {
874 size_t newLength = 0;
875 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
881 size_t newLength = 0;
882 char *utf8 = xcb_compound_text_to_utf8(str, length, &newLength);
889static void xim_disconnected(G_GNUC_UNUSED xcb_xim_t *im,
890 G_GNUC_UNUSED
void *user_data) {
894static void create_ic_callback(xcb_xim_t *im, xcb_xic_t new_ic,
895 G_GNUC_UNUSED
void *user_data) {
898 xcb_xim_set_ic_focus(im,
xcb->ic);
906 static xcb_point_t spot = {.x = 0, .y = 0};
907 if (spot.x != new_x || spot.y != new_y) {
910 xcb_xim_nested_list nested = xcb_xim_create_nested_list(
911 xcb->im, XCB_XIM_XNSpotLocation, &spot, NULL);
912 xcb_xim_set_ic_values(
xcb->im,
xcb->ic, NULL, NULL, XCB_XIM_XNClientWindow,
913 &
CacheState.main_window, XCB_XIM_XNFocusWindow,
914 &
CacheState.main_window, XCB_XIM_XNPreeditAttributes,
920static void open_xim_callback(xcb_xim_t *im, G_GNUC_UNUSED
void *user_data) {
922 uint32_t input_style = XCB_IM_PreeditPosition | XCB_IM_StatusArea;
928 xcb_xim_nested_list nested =
929 xcb_xim_create_nested_list(im, XCB_XIM_XNSpotLocation, &spot, NULL);
931 im, create_ic_callback, NULL, XCB_XIM_XNInputStyle, &input_style,
932 XCB_XIM_XNClientWindow, &
CacheState.main_window, XCB_XIM_XNFocusWindow,
933 &
CacheState.main_window, XCB_XIM_XNPreeditAttributes, &nested, NULL);
939 if (
CacheState.entry_history_enable == FALSE) {
946 gchar *path = g_build_filename(
cache_dir,
"rofi-entry-history.txt", NULL);
947 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
948 FILE *fp = fopen(path,
"r");
953 while ((nread = getline(&line, &len, fp)) != -1) {
957 if (line[nread - 1] ==
'\n') {
958 line[nread - 1] =
'\0';
982 if (
CacheState.entry_history_enable == FALSE) {
987 int max_history = 20;
996 gchar *path = g_build_filename(
cache_dir,
"rofi-entry-history.txt", NULL);
997 g_debug(
"Entry filename output: '%s'", path);
998 FILE *fp = fopen(path,
"w");
1000 gssize start = MAX(0, (
CacheState.entry_history_length - max_history));
1001 for (gssize i = start; i <
CacheState.entry_history_length; i++) {
1002 if (strlen(
CacheState.entry_history[i].string) > 0) {
1003 fprintf(fp,
"%s\n",
CacheState.entry_history[i].string);
1012 for (ssize_t i = 0; i <
CacheState.entry_history_length; i++) {
1025 uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
1026 XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |
1027 XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
1028 uint32_t xcb_event_masks =
1029 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
1030 XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS |
1031 XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
1032 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE |
1033 XCB_EVENT_MASK_BUTTON_1_MOTION | XCB_EVENT_MASK_POINTER_MOTION;
1035 uint32_t selval[] = {XCB_BACK_PIXMAP_NONE, 0,
1036 XCB_GRAVITY_STATIC, XCB_BACKING_STORE_NOT_USEFUL,
1037 xcb_event_masks,
map};
1040 if (
config.enable_imdkit) {
1041 xcb_xim_set_im_callback(
xcb->im, &xim_callback, NULL);
1044 xcb_xim_open(
xcb->im, open_xim_callback,
true, NULL);
1048 xcb_window_t box_window = xcb_generate_id(
xcb->connection);
1049 xcb_void_cookie_t cc = xcb_create_window_checked(
1051 0, 200, 100, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
visual->visual_id, selmask,
1053 xcb_generic_error_t *error;
1054 error = xcb_request_check(
xcb->connection, cc);
1056 g_error(
"xcb_create_window() failed error=0x%x\n", error->error_code);
1060 TICK_N(
"xcb create window");
1062 xcb_create_gc(
xcb->connection,
CacheState.gc, box_window, 0, 0);
1070 CacheState.edit_surf = cairo_xcb_surface_create(
1074 TICK_N(
"create cairo surface");
1076 cairo_font_options_t *fo = cairo_font_options_create();
1078 cairo_surface_get_font_options(
CacheState.edit_surf, fo);
1080 PangoContext *p = pango_cairo_create_context(
CacheState.edit_draw);
1082 pango_cairo_context_set_font_options(p, fo);
1083 TICK_N(
"pango cairo font setup");
1090 PangoFontMap *font_map = pango_cairo_font_map_get_default();
1091 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map,
1099 dpi = (
xcb->screen->height_in_pixels * 25.4) /
1100 (
double)(
xcb->screen->height_in_millimeters);
1103 g_debug(
"Auto-detected DPI: %.2lf", dpi);
1104 PangoFontMap *font_map = pango_cairo_font_map_get_default();
1105 pango_cairo_font_map_set_resolution((PangoCairoFontMap *)font_map, dpi);
1109 PangoFontMap *font_map = pango_cairo_font_map_get_default();
1111 pango_cairo_font_map_get_resolution((PangoCairoFontMap *)font_map);
1119 PangoFontDescription *pfd = pango_font_description_from_string(font);
1121 pango_context_set_font_description(p, pfd);
1123 pango_font_description_free(pfd);
1125 PangoLanguage *l = pango_language_get_default();
1126 pango_context_set_language(p, l);
1127 TICK_N(
"configure font");
1133 cairo_font_options_destroy(fo);
1138 xcb_atom_t atoms[] = {
xcb->ewmh._NET_WM_STATE_MODAL};
1141 sizeof(atoms) /
sizeof(xcb_atom_t));
1143 &(
xcb->ewmh._NET_WM_WINDOW_TYPE_UTILITY), 1);
1146 xcb_window_t active_window;
1147 xcb_get_property_cookie_t awc;
1148 awc = xcb_ewmh_get_active_window(&
xcb->ewmh,
xcb->screen_nbr);
1150 if (xcb_ewmh_get_active_window_reply(&
xcb->ewmh, awc, &active_window,
1152 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE, box_window,
1153 XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1,
1158 &(
xcb->ewmh._NET_WM_STATE_ABOVE), 1);
1159 uint32_t values[] = {1};
1160 xcb_change_window_attributes(
xcb->connection, box_window,
1161 XCB_CW_OVERRIDE_REDIRECT, values);
1164 &(
xcb->ewmh._NET_WM_WINDOW_TYPE_NORMAL), 1);
1168 TICK_N(
"setup window attributes");
1172 xcb_atom_t atoms[] = {
xcb->ewmh._NET_WM_STATE_FULLSCREEN,
1173 xcb->ewmh._NET_WM_STATE_ABOVE};
1175 sizeof(atoms) /
sizeof(xcb_atom_t));
1178 xcb_atom_t protocols[] = {
netatoms[WM_TAKE_FOCUS]};
1179 xcb_icccm_set_wm_protocols(
xcb->connection, box_window,
1180 xcb->ewmh.WM_PROTOCOLS, G_N_ELEMENTS(protocols),
1183 TICK_N(
"setup window fullscreen");
1186 const char wm_class_name[] =
"rofi\0Rofi";
1187 xcb_icccm_set_wm_class(
xcb->connection, box_window,
sizeof(wm_class_name),
1190 TICK_N(
"setup window name and class");
1191 const char *transparency =
1196 if (
xcb->sncontext != NULL) {
1197 sn_launchee_context_setup_window(
xcb->sncontext,
CacheState.main_window);
1199 TICK_N(
"setup startup notification");
1204 pid_t pid = getpid();
1205 xcb_ewmh_set_wm_pid(&(
xcb->ewmh),
CacheState.main_window, pid);
1208 const char *hostname = g_get_host_name();
1209 char *ahost = g_hostname_to_ascii(hostname);
1210 if (ahost != NULL) {
1211 xcb_icccm_set_wm_client_machine(
xcb->connection,
CacheState.main_window,
1212 XCB_ATOM_STRING, 8, strlen(ahost), ahost);
1231 "width", state->
width);
1274 if (selected < state->filtered_lines) {
1308 if (
config.on_selection_changed == NULL)
1313 &fstate, NULL, TRUE);
1323 unsigned int index,
void *udata) {
1325 if (index < state->filtered_lines) {
1332 if (index < state->filtered_lines) {
1335 &fstate, NULL, TRUE);
1343 if (index < state->filtered_lines) {
1347 cairo_surface_t *surf_icon =
1359 GList *add_list = NULL;
1362 &fstate, &add_list, TRUE);
1367 cairo_surface_t *surf_icon =
1378 pango_attr_list_ref(list);
1380 list = pango_attr_list_new();
1385 {0.0, 0.0, 0.0, 0.0}};
1390 for (GList *iter = g_list_first(add_list); iter != NULL;
1391 iter = g_list_next(iter)) {
1392 pango_attr_list_insert(list, (PangoAttribute *)(iter->data));
1395 pango_attr_list_unref(list);
1398 g_list_free(add_list);
1419 g_debug(
"Redraw view");
1422 cairo_set_operator(d, CAIRO_OPERATOR_SOURCE);
1425 cairo_set_source_surface(d,
CacheState.fake_bg, 0.0, 0.0);
1427 cairo_set_source_surface(d,
CacheState.fake_bg,
1433 cairo_set_source_rgba(d, 0, 0, 0, 0.0);
1437 cairo_set_operator(d, CAIRO_OPERATOR_OVER);
1443 if (
config.enable_imdkit) {
1472 if (state->
sw == NULL) {
1473 return G_SOURCE_REMOVE;
1475 GTimer *timer = g_timer_new();
1481 TICK_N(
"Filter reload rows");
1486 TICK_N(
"Filter tokenize");
1492 glong plen = pattern ? g_utf8_strlen(pattern, -1) : 0;
1506 unsigned int nt = MAX(1, state->
num_lines / 500);
1509 nt = MIN(nt,
config.threads * 4);
1513 g_mutex_init(&mutex);
1515 unsigned int count = nt;
1516 unsigned int steps = (state->
num_lines + nt) / nt;
1517 for (
unsigned int i = 0; i < nt; i++) {
1518 states[i].
state = state;
1519 states[i].
start = i * steps;
1521 states[i].
count = 0;
1522 states[i].
cond = &cond;
1523 states[i].
mutex = &mutex;
1525 states[i].
plen = plen;
1528 states[i].
st.
free = NULL;
1531 g_thread_pool_push(
tpool, &states[i], NULL);
1538 g_mutex_lock(&mutex);
1540 g_cond_wait(&cond, &mutex);
1542 g_mutex_unlock(&mutex);
1544 g_cond_clear(&cond);
1545 g_mutex_clear(&mutex);
1546 for (
unsigned int i = 0; i < nt; i++) {
1547 if (j != states[i].start) {
1549 sizeof(
unsigned int) * (states[i].
count));
1551 j += states[i].
count;
1562 double elapsed = g_timer_elapsed(timer, NULL);
1567 for (
unsigned int i = 0; i < state->
num_lines; i++) {
1572 TICK_N(
"Filter matching done");
1581 char *r = g_strdup_printf(
"%u", state->
num_lines);
1585 TICK_N(
"Update filter lines");
1597 if (height != state->
height) {
1601 g_debug(
"Resize based on re-filter");
1603 TICK_N(
"Filter resize window based on window ");
1608 g_timer_destroy(timer);
1609 return G_SOURCE_REMOVE;
1615 g_source_remove(
CacheState.refilter_timeout);
1618 if (
CacheState.max_refilter_time > (
config.refilter_timeout_limit / 1000.0) &&
1623 "Filtering took %f seconds ( %f ), switching to delayed filter\n",
1634 "Filtering took %f seconds , switching back to instant filter\n",
1643 g_source_remove(
CacheState.refilter_timeout);
1657 if (state && state->
finalize != NULL) {
1670 if (
CacheState.entry_history_enable && state) {
1687 xcb_convert_selection(
xcb->connection,
CacheState.main_window,
1688 XCB_ATOM_PRIMARY,
xcb->ewmh.UTF8_STRING,
1689 xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1690 xcb_flush(
xcb->connection);
1693 xcb_convert_selection(
xcb->connection,
CacheState.main_window,
1695 xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME);
1696 xcb_flush(
xcb->connection);
1701 if (selected < state->filtered_lines) {
1704 data = g_strdup(state->
text->
text);
1708 xcb_set_selection_owner(
xcb->connection,
CacheState.main_window,
1709 netatoms[CLIPBOARD], XCB_CURRENT_TIME);
1710 xcb_flush(
xcb->connection);
1742 if (selected < state->filtered_lines) {
1761 if (selected < state->filtered_lines) {
1779 if (index < state->filtered_lines) {
1807 if (selected < state->filtered_lines) {
1885 }
else if (rc == 2) {
1894 if (selected < state->filtered_lines) {
1924 if (selected < state->filtered_lines) {
2015 if (target == NULL) {
2049 if (target == NULL) {
2053 if (target == NULL) {
2117 gboolean find_mouse_target) {
2125 if (find_mouse_target) {
2129 if (target != NULL) {
2138 if (find_mouse_target) {
2146 if (
config.on_entry_accepted == NULL)
2155 &fstate, NULL, TRUE);
2164 if (
config.on_menu_canceled == NULL)
2169 if (
config.on_mode_changed == NULL)
2185 if (state == NULL) {
2205 xcb_configure_notify_event_t *xce) {
2207 if (state->
x != xce->x || state->
y != xce->y) {
2212 if (state->
width != xce->width || state->
height != xce->height) {
2213 state->
width = xce->width;
2214 state->
height = xce->height;
2225 cairo_xcb_surface_create(
xcb->connection,
CacheState.edit_pixmap,
2228 g_debug(
"Re-size window based external request: %d %d", state->
width,
2275 G_GNUC_UNUSED gint y, G_GNUC_UNUSED
void *user_data) {
2288 if (
id != UINT32_MAX) {
2304 G_GNUC_UNUSED gint y, G_GNUC_UNUSED
void *user_data) {
2307 for (i = 0; i < state->
num_modes; i++) {
2346 char *defaults = NULL;
2352 if (strcmp(name,
"mainbox") == 0) {
2355 if (
config.sidebar_mode) {
2356 defaults =
"inputbar,message,listview,mode-switcher";
2358 defaults =
"inputbar,message,listview";
2364 else if (strcmp(name,
"inputbar") == 0) {
2367 defaults =
"prompt,entry,overlay,case-indicator";
2373 else if (strcmp(name,
"prompt") == 0) {
2374 if (state->
prompt != NULL) {
2375 g_error(
"Prompt widget can only be added once to the layout.");
2385 }
else if (strcmp(name,
"num-rows") == 0) {
2391 }
else if (strcmp(name,
"num-filtered-rows") == 0) {
2397 }
else if (strcmp(name,
"textbox-current-entry") == 0) {
2403 }
else if (strcmp(name,
"icon-current-entry") == 0) {
2411 else if (strcmp(name,
"case-indicator") == 0) {
2413 g_error(
"Case indicator widget can only be added once to the layout.");
2426 else if (strcmp(name,
"entry") == 0) {
2427 if (state->
text != NULL) {
2428 g_error(
"Entry textbox widget can only be added once to the layout.");
2442 else if (strcmp(name,
"message") == 0) {
2444 g_error(
"Message widget can only be added once to the layout.");
2458 else if (strcmp(name,
"listview") == 0) {
2460 g_error(
"Listview widget can only be added once to the layout.");
2478 else if (strcmp(name,
"mode-switcher") == 0 || strcmp(name,
"sidebar") == 0) {
2480 g_error(
"Mode-switcher can only be added once to the layout.");
2488 for (
unsigned int j = 0; j < state->
num_modes; j++) {
2498 }
else if (g_ascii_strcasecmp(name,
"overlay") == 0) {
2504 }
else if (g_ascii_strncasecmp(name,
"textbox", 7) == 0) {
2508 }
else if (g_ascii_strncasecmp(name,
"button", 6) == 0) {
2514 }
else if (g_ascii_strncasecmp(name,
"icon", 4) == 0) {
2533 char **a = g_strsplit(defaults,
",", 0);
2534 for (
int i = 0; a && a[i]; i++) {
2540 for (
const GList *iter = g_list_first(list); iter != NULL;
2541 iter = g_list_next(iter)) {
2544 g_list_free_full(list, g_free);
2550 xcb_query_pointer_cookie_t pointer_cookie =
2552 xcb_query_pointer_reply_t *pointer_reply =
2553 xcb_query_pointer_reply(
xcb->connection, pointer_cookie, NULL);
2555 if (pointer_reply == NULL) {
2560 pointer_reply->win_y,
config.hover_select);
2562 free(pointer_reply);
2576 state->
quit = FALSE;
2586 g_debug(
"Disable entry history, because password setup.");
2588 if (
config.disable_history) {
2590 g_debug(
"Disable entry history, because history disable flag.");
2603 TICK_N(
"Startup notification");
2606 TICK_N(
"Get active monitor");
2615 for (
const GList *iter = list; iter != NULL; iter = g_list_next(iter)) {
2617 (
const char *)iter->data);
2619 g_list_free_full(list, g_free);
2622 if (state->
text && input) {
2642 state->
quit = FALSE;
2648 xcb_flush(
xcb->connection);
2657 if (
xcb->sncontext != NULL) {
2658 sn_launchee_context_complete(
xcb->sncontext);
2664 if (
config.on_menu_error == NULL)
2688 NORMAL, (msg != NULL) ? msg :
"", 0, 0);
2708 if (
xcb->sncontext != NULL) {
2709 sn_launchee_context_complete(
xcb->sncontext);
2721 if (
CacheState.main_window != XCB_WINDOW_NONE) {
2731 g_debug(
"Cleanup.");
2737 g_source_remove(
CacheState.refilter_timeout);
2764 if (
CacheState.main_window != XCB_WINDOW_NONE) {
2765 g_debug(
"Unmapping and free'ing window");
2770 xcb_destroy_window(
xcb->connection,
CacheState.main_window);
2773 if (
map != XCB_COLORMAP_NONE) {
2774 xcb_free_colormap(
xcb->connection,
map);
2775 map = XCB_COLORMAP_NONE;
2777 xcb_flush(
xcb->connection);
2778 g_assert(g_queue_is_empty(&(
CacheState.views)));
2784 gpointer data G_GNUC_UNUSED) {
2797 if (GPOINTER_TO_UINT(data) == 1) {
2799 g_debug(
"Glib thread-pool bug, received pointer with value 1.");
2810 TICK_N(
"Setup Threadpool, start");
2811 if (
config.threads == 0) {
2813 long procs = sysconf(_SC_NPROCESSORS_CONF);
2815 config.threads = MIN(procs, 128l);
2819 GError *error = NULL;
2823 if (error == NULL) {
2825 g_thread_pool_set_max_idle_time(60000);
2827 g_thread_pool_set_max_threads(
tpool,
config.threads, &error);
2830 if (error != NULL) {
2831 g_warning(
"Failed to setup thread pool: '%s'", error->message);
2832 g_error_free(error);
2836 TICK_N(
"Setup Threadpool, done");
2841 g_thread_pool_free(
tpool, TRUE, FALSE);
2854 return G_SOURCE_REMOVE;
2897 PangoEllipsizeMode mode) {
2916 for (
unsigned int j = 0; j < state->
num_modes; j++) {
2932 ssize_t len = strlen(title);
2933 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE,
2935 xcb->ewmh.UTF8_STRING, 8, len, title);
2936 xcb_change_property(
xcb->connection, XCB_PROP_MODE_REPLACE,
2937 CacheState.main_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING,
PangoAttrList * helper_token_match_get_pango_attr(RofiHighlightColorStyle th, rofi_int_matcher **tokens, const char *input, PangoAttrList *retv)
gboolean helper_validate_font(PangoFontDescription *pfd, const char *font)
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
unsigned int levenshtein(const char *needle, const glong needlelen, const char *haystack, const glong haystacklen, int case_sensitive)
Property * rofi_theme_find_property(ThemeWidget *wid, PropertyType type, const char *property, gboolean exact)
gboolean helper_execute_command(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context)
void helper_select_next_matching_mode(void)
void helper_tokenize_free(rofi_int_matcher **tokens)
const char * helper_get_matching_mode_str(void)
gboolean helper_execute(const char *wd, char **args, const char *error_precmd, const char *error_cmd, RofiHelperExecuteContext *context)
ThemeWidget * rofi_config_find_widget(const char *name, const char *state, gboolean exact)
int helper_parse_setup(char *string, char ***output, int *length,...)
void helper_select_previous_matching_mode(void)
char * rofi_expand_path(const char *input)
int parse_case_sensitivity(const char *input)
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str, glong slen, int case_sensitive)
guint key_binding_get_action_from_name(const char *name)
MouseBindingMouseDefaultAction
@ SCOPE_MOUSE_LISTVIEW_ELEMENT
@ SCOPE_MOUSE_MODE_SWITCHER
@ TOGGLE_CASE_SENSITIVITY
char * mode_preprocess_input(Mode *mode, const char *input)
cairo_surface_t * mode_get_icon(Mode *mode, unsigned int selected_line, unsigned int height)
const char * mode_get_display_name(const Mode *mode)
unsigned int mode_get_num_entries(const Mode *mode)
char * mode_get_message(const Mode *mode)
int mode_token_match(const Mode *mode, rofi_int_matcher **tokens, unsigned int selected_line)
char * mode_get_display_value(const Mode *mode, unsigned int selected_line, int *state, GList **attribute_list, int get_entry)
char * mode_get_completion(const Mode *mode, unsigned int selected_line)
const Mode * rofi_get_mode(unsigned int index)
void rofi_quit_main_loop(void)
unsigned int rofi_get_num_enabled_modes(void)
void textbox_font(textbox *tb, TextBoxFontType tbft)
int textbox_keybinding(textbox *tb, KeyBindingAction action)
void textbox_set_pango_attributes(textbox *tb, PangoAttrList *list)
const char * textbox_get_visible_text(const textbox *tb)
int textbox_get_cursor(const textbox *tb)
void textbox_cursor(textbox *tb, int pos)
void textbox_set_pango_context(const char *font, PangoContext *p)
textbox * textbox_create(widget *parent, WidgetType type, const char *name, TextboxFlags flags, TextBoxFontType tbft, const char *text, double xalign, double yalign)
void textbox_cursor_end(textbox *tb)
gboolean textbox_append_text(textbox *tb, const char *pad, const int pad_len)
PangoAttrList * textbox_get_pango_attributes(textbox *tb)
void textbox_text(textbox *tb, const char *text)
int textbox_get_cursor_x_pos(const textbox *tb)
char * textbox_get_text(const textbox *tb)
void rofi_view_cleanup(void)
void rofi_view_set_overlay(RofiViewState *state, const char *text)
void __create_window(MenuFlags menu_flags)
void rofi_view_clear_input(RofiViewState *state)
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Mode * rofi_view_get_mode(RofiViewState *state)
void rofi_view_hide(void)
void rofi_view_reload(void)
xcb_window_t rofi_view_get_window(void)
void rofi_view_remove_active(RofiViewState *state)
void rofi_view_set_overlay_timeout(RofiViewState *state, const char *text)
int rofi_view_error_dialog(const char *msg, int markup)
void rofi_view_set_active(RofiViewState *state)
void rofi_view_queue_redraw(void)
RofiViewState * rofi_view_get_active(void)
void rofi_view_restart(RofiViewState *state)
void rofi_view_handle_text(RofiViewState *state, char *text)
void rofi_view_trigger_action(RofiViewState *state, BindingsScope scope, guint action)
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
unsigned int rofi_view_get_completed(const RofiViewState *state)
gboolean rofi_view_check_action(RofiViewState *state, BindingsScope scope, guint action)
const char * rofi_view_get_user_input(const RofiViewState *state)
void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y, gboolean find_mouse_target)
void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target)
void rofi_view_finalize(RofiViewState *state)
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
void rofi_view_temp_configure_notify(RofiViewState *state, xcb_configure_notify_event_t *xce)
void rofi_view_frame_callback(void)
void rofi_view_free(RofiViewState *state)
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
unsigned int rofi_view_get_next_position(const RofiViewState *state)
void rofi_view_maybe_update(RofiViewState *state)
gboolean rofi_set_im_window_pos(int new_x, int new_y)
void rofi_capture_screenshot(void)
void rofi_view_workers_initialize(void)
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)
void rofi_view_set_window_title(const char *title)
void rofi_view_ellipsize_listview(RofiViewState *state, PangoEllipsizeMode mode)
void rofi_view_get_current_monitor(int *width, int *height)
void rofi_view_workers_finalize(void)
void box_add(box *wid, widget *child, gboolean expand)
box * box_create(widget *parent, const char *name, RofiOrientation type)
void container_add(container *cont, widget *child)
container * container_create(widget *parent, const char *name)
void icon_set_surface(icon *icon_widget, cairo_surface_t *surf)
icon * icon_create(widget *parent, const char *name)
void listview_nav_page_next(listview *lv)
void listview_set_fixed_num_lines(listview *lv)
struct _listview listview
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)
void listview_set_num_elements(listview *lv, unsigned int rows)
void listview_nav_right(listview *lv)
void listview_set_mouse_activated_cb(listview *lv, listview_mouse_activated_cb cb, void *udata)
void listview_toggle_ellipsizing(listview *lv)
void listview_set_ellipsize(listview *lv, PangoEllipsizeMode mode)
void listview_set_selected(listview *lv, unsigned int selected)
void listview_set_max_lines(listview *lv, unsigned int max_lines)
void listview_nav_left(listview *lv)
void listview_set_scroll_type(listview *lv, ScrollType type)
void listview_nav_prev(listview *lv)
unsigned int listview_get_selected(listview *lv)
void listview_set_filtered(listview *lv, gboolean filtered)
void listview_nav_up(listview *lv)
void listview_nav_next(listview *lv)
void listview_nav_page_prev(listview *lv)
void listview_set_selection_changed_callback(listview *lv, listview_selection_changed_callback cb, void *udata)
void listview_nav_down(listview *lv)
@ ROFI_ORIENTATION_HORIZONTAL
@ ROFI_ORIENTATION_VERTICAL
struct _thread_state thread_state
GList * list_of_warning_msgs
void process_result(RofiViewState *state)
#define DEFAULT_MENU_WIDTH
unsigned int filtered_lines
icon * icon_current_entry
struct RofiViewState::@141050056035150177024355252222311351137250305333 mouse
unsigned int previous_line
void(* finalize)(struct RofiViewState *state)
textbox * tb_filtered_rows
rofi_int_matcher ** tokens
textbox * tb_current_entry
unsigned int selected_line
KeyBindingAction prev_action
void(* callback)(struct _thread_state *t, gpointer data)
int rofi_theme_get_integer(const widget *wid, const char *property, int def)
RofiHighlightColorStyle rofi_theme_get_highlight(widget *wid, const char *property, RofiHighlightColorStyle th)
int rofi_theme_get_position(const widget *wid, const char *property, int def)
int distance_get_pixel(RofiDistance d, RofiOrientation ori)
int rofi_theme_get_boolean(const widget *wid, const char *property, int def)
RofiDistance rofi_theme_get_distance(const widget *wid, const char *property, int def)
GList * rofi_theme_get_list_strings(const widget *wid, const char *property)
const char * rofi_theme_get_string(const widget *wid, const char *property, const char *def)
static void rofi_view_call_thread(gpointer data, gpointer user_data)
cairo_surface_t * fake_bg
static void rofi_view_nav_last(RofiViewState *state)
struct @303212127125276242164050310102020023110254275240 CacheState
static gboolean rofi_view_repaint(G_GNUC_UNUSED void *data)
static void rofi_view_set_user_timeout(G_GNUC_UNUSED gpointer data)
static gboolean rofi_view_reload_idle(G_GNUC_UNUSED gpointer data)
static gboolean bench_update(void)
static void rofi_error_user_callback(const char *msg)
static char * get_matching_state(RofiViewState *state)
struct _thread_state_view thread_state_view
guint refilter_timeout_count
static void rofi_view_nav_row_select(RofiViewState *state)
static void rofi_view_listview_mouse_activated_cb(listview *lv, gboolean custom, void *udata)
EntryHistoryIndex * entry_history
static gboolean rofi_view_overlay_timeout(G_GNUC_UNUSED gpointer user_data)
static void screenshot_taken_user_callback(const char *path)
cairo_surface_t * edit_surf
static void rofi_view_add_widget(RofiViewState *state, widget *parent_widget, const char *name)
static void update_callback(textbox *t, icon *ico, unsigned int index, void *udata, TextBoxFontType *type, gboolean full)
static void rofi_view_nav_row_tab(RofiViewState *state)
static void rofi_view_setup_fake_transparency(widget *win, const char *const fake_background)
static void input_history_save(void)
gboolean entry_history_enable
static void rofi_view_reload_message_bar(RofiViewState *state)
static void rofi_view_nav_first(RofiViewState *state)
static gboolean rofi_view_refilter_real(RofiViewState *state)
static void page_changed_callback(void)
void rofi_view_update(RofiViewState *state, gboolean qr)
static const int loc_transtable[9]
static RofiViewState * __rofi_view_state_create(void)
static void rofi_view_trigger_global_action(KeyBindingAction action)
static void rofi_view_input_changed(void)
gssize entry_history_index
static void filter_elements(thread_state *ts, G_GNUC_UNUSED gpointer user_data)
void process_result(RofiViewState *state)
static void rofi_view_update_prompt(RofiViewState *state)
static struct @224217335044137010276353040043060036143107331103 BenchMark
static gboolean rofi_view_user_timeout(G_GNUC_UNUSED gpointer data)
static void rofi_view_refilter(RofiViewState *state)
X11CursorType cursor_type
static int rofi_view_calculate_height(RofiViewState *state)
RofiViewState * current_active_menu
static void rofi_thread_pool_state_free(gpointer data)
gssize entry_history_length
static int rofi_thread_workers_sort(gconstpointer a, gconstpointer b, gpointer data G_GNUC_UNUSED)
static void rofi_view_calculate_window_position(RofiViewState *state)
static void rofi_view_set_cursor(RofiCursorType type)
static void selection_changed_user_callback(unsigned int index, RofiViewState *state)
static void rofi_view_take_action(const char *name)
static void selection_changed_callback(G_GNUC_UNUSED listview *lv, unsigned int index, void *udata)
static void rofi_quit_user_callback(RofiViewState *state)
static void rofi_view_ping_mouse(RofiViewState *state)
static void rofi_view_window_update_size(RofiViewState *state)
static void rofi_view_calculate_window_width(RofiViewState *state)
static X11CursorType rofi_cursor_type_to_x11_cursor_type(RofiCursorType type)
static RofiCursorType rofi_view_resolve_cursor(RofiViewState *state, gint x, gint y)
static int lev_sort(const void *p1, const void *p2, void *arg)
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)
static void _rofi_view_reload_row(RofiViewState *state)
static void input_history_initialize(void)
static void rofi_view_refilter_force(RofiViewState *state)
int monitor_active(workarea *mon)
void display_early_cleanup(void)
cairo_surface_t * x11_helper_get_screenshot_surface(void)
void rofi_xcb_revert_input_focus(void)
cairo_surface_t * x11_helper_get_bg_surface(void)
void rofi_xcb_set_input_focus(xcb_window_t w)
void x11_set_cursor(xcb_window_t window, X11CursorType type)
void cairo_image_surface_blur(cairo_surface_t *surface, int radius, double deviation)
xcb_window_t xcb_stuff_get_root_window(void)
void window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count)
void xcb_stuff_set_clipboard(char *data)
void x11_disable_decoration(xcb_window_t window)
xcb_atom_t netatoms[NUM_NETATOMS]
xcb_visualtype_t * visual
struct _workarea workarea