29#define G_LOG_DOMAIN "Modes.DMenu"
45#include <gio/gunixinputstream.h>
61static cairo_surface_t *
65static inline unsigned int bitget(uint32_t
const *
const array,
67 uint32_t bit = index % 32;
68 uint32_t val = array[index / 32];
69 return (val >> bit) & 1;
72static inline void bittoggle(uint32_t *
const array,
unsigned int index) {
73 uint32_t bit = index % 32;
74 uint32_t *v = &array[index / 32];
120#define BLOCK_LINES_SIZE 2048
130 if ((*block) == NULL) {
131 (*block) = g_malloc0(
sizeof(
Block));
133 (*block)->length = 0;
135 gsize data_len = len;
137 (*block)->values[(*block)->length].icon_fetch_uid = 0;
138 (*block)->values[(*block)->length].icon_fetch_size = 0;
139 (*block)->values[(*block)->length].icon_fetch_scale = 0;
140 (*block)->values[(*block)->length].icon_fallback_index = 0;
141 (*block)->values[(*block)->length].icon_name = NULL;
142 (*block)->values[(*block)->length].meta = NULL;
143 (*block)->values[(*block)->length].info = NULL;
144 (*block)->values[(*block)->length].nonselectable = FALSE;
145 (*block)->values[(*block)->length].permanent = FALSE;
147 while (end < data + len && *end !=
'\0') {
150 if (end != data + len) {
151 data_len = end - data;
153 end + 1, len - data_len);
156 (*block)->values[(*block)->length].entry = utfstr;
162 gsize data_len = len;
181 while (end < data + len && *end !=
'\0') {
184 if (end != data + len) {
185 data_len = end - data;
187 end + 1, len - data_len);
206 gpointer user_data) {
210 if ((condition & G_IO_IN) != G_IO_IN) {
211 return G_SOURCE_CONTINUE;
214 if (read(fd, &command, 1) == 1) {
215 if (command ==
'r') {
217 gboolean changed = FALSE;
220 while ((block = g_async_queue_try_pop(pd->
async_queue)) != NULL) {
236 }
else if (command ==
'q') {
242 return G_SOURCE_CONTINUE;
249 while (pre_read > 0 &&
268 GTimer *tim = g_timer_new();
274 struct timeval tv = {.tv_sec = 0, .tv_usec = 250000};
278 FD_SET(pd->
pipefd[0], &rfds);
280 int retval = select(MAX(fd, pd->
pipefd[0]) + 1, &rfds, NULL, NULL, &tv);
282 g_warning(
"select failed, giving up.");
286 if (FD_ISSET(pd->
pipefd[0], &rfds)) {
290 if (FD_ISSET(fd, &rfds)) {
291 ssize_t readbytes = 0;
292 if ((nread + 1024) > len) {
293 line = g_realloc(line, (len + 2048));
296 readbytes = read(fd, &line[nread], 1023);
305 memmove(&line[0], &line[i + 1], nread - (i + 1));
309 double elapsed = g_timer_elapsed(tim, NULL);
351 g_timer_destroy(tim);
366 const unsigned int index,
367 gboolean multi_select) {
370 if (index < pd->num_selected_list &&
377 return g_strdup(input);
383 for (; splitted && splitted[ns]; ns++) {
386 GString *str_retv = g_string_new(
"");
389 if (index < pd->num_selected_list &&
397 unsigned int col_index =
398 (
unsigned int)g_ascii_strtoull(pd->
columns[i], NULL, 10);
399 if (col_index <= ns && col_index > 0) {
401 g_string_append(str_retv, splitted[col_index - 1]);
403 g_string_append_c(str_retv,
'\t');
404 g_string_append(str_retv, splitted[col_index - 1]);
408 g_strfreev(splitted);
409 retv = str_retv->str;
410 g_string_free(str_retv, FALSE);
414static inline unsigned int get_index(
unsigned int length,
int index) {
418 if (((
unsigned int)-index) <= length) {
419 return length + index;
429 if (retv[index].display) {
437 G_GNUC_UNUSED GList **list,
int get_entry) {
445 if (index >= start && index <= stop) {
453 if (index >= start && index <= stop) {
457 if (index < pd->num_selected_list &&
470 char *my_retv = NULL;
471 if (retv[index].display) {
512 .cfg_name_key =
"display-combi",
521 ._preprocess_input = NULL,
523 .private_data = NULL,
525 .display_name =
"dmenu",
545 if (
find_arg(
"-multi-select") >= 0) {
581 p->
name = g_strdup(
"lines");
585 g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
588 g_hash_table_replace(table, p->
name, p);
590 g_hash_table_destroy(table);
612 pd->
fd = STDIN_FILENO;
615 pd->
fd = open(str, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
617 char *msg = g_markup_printf_escaped(
618 "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
628 if (pipe(pd->
pipefd) == -1) {
629 g_error(
"Failed to create pipe");
632 g_error(
"Failed to create pipe");
648 char *msg = g_markup_printf_escaped(
649 "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
661 gchar *columns = NULL;
663 pd->
columns = g_strsplit(columns,
",", 0);
671 unsigned int index) {
683 pango_parse_markup(rmpd->
cmd_list[index].
entry, -1, 0, NULL, &esc, NULL,
692 for (
int j = 0; match && tokens[j] != NULL; j++) {
696 if (test == tokens[j]->invert && rmpd->
cmd_list[index].
meta) {
720 unsigned int selected_line,
721 unsigned int height) {
725 g_return_val_if_fail(pd->
cmd_list != NULL, NULL);
733 cairo_surface_t *surface = NULL;
736 gboolean query_done =
739 if (surface != NULL) {
741 }
else if (query_done) {
749 char *current_icon = NULL;
751 int icon_count = g_strv_length(dr->
icon_name);
779 write(pd->
pipefd[1],
"q", 1);
785 while ((block = g_async_queue_try_pop_unlocked(pd->
async_queue)) != NULL) {
801 }
else if (retv >= 10) {
821 const char *cmd = input;
854 restart = (
find_arg(
"-only-match") >= 0);
862 g_realloc(pd->
selected_list,
sizeof(uint32_t) * (new_length));
868 (new_length - old_length) *
sizeof(uint32_t));
926 g_realloc(pd->
selected_list,
sizeof(uint32_t) * (new_length));
932 (new_length - old_length) *
sizeof(uint32_t));
991 if (
find_arg(
"-markup-rows") >= 0) {
996 if (cmd_list_length == 0) {
1010 char *select = NULL;
1012 if (select != NULL) {
1016 for (i = 0; i < cmd_list_length; i++) {
1029 for (i = 0; i < cmd_list_length; i++) {
1044 if (
find_arg(
"-keep-right") >= 0) {
1047 char *ellipsize_mode = NULL;
1048 if (
find_arg_str(
"-ellipsize-mode", &ellipsize_mode) >= 0) {
1049 if (ellipsize_mode) {
1050 if (g_ascii_strcasecmp(ellipsize_mode,
"start") == 0) {
1052 }
else if (g_ascii_strcasecmp(ellipsize_mode,
"middle") == 0) {
1054 }
else if (g_ascii_strcasecmp(ellipsize_mode,
"end") == 0) {
1057 g_warning(
"Unrecognized ellipsize mode: '%s'", ellipsize_mode);
1071 int is_term = isatty(fileno(stdout));
1073 "-mesg",
"[string]",
1074 "Print a small user message under the prompt (uses pango markup)", NULL,
1076 print_help_msg(
"-p",
"[string]",
"Prompt to display left of entry field",
1078 print_help_msg(
"-selected-row",
"[integer]",
"Select row", NULL, is_term);
1079 print_help_msg(
"-format",
"[string]",
"Output format string",
"s", is_term);
1080 print_help_msg(
"-u",
"[list]",
"List of row indexes to mark urgent", NULL,
1082 print_help_msg(
"-a",
"[list]",
"List of row indexes to mark active", NULL,
1084 print_help_msg(
"-l",
"[integer] ",
"Number of rows to display", NULL,
1086 print_help_msg(
"-window-title",
"[string] ",
"Set the dmenu window title",
1088 print_help_msg(
"-i",
"",
"Set filter to be case insensitive", NULL, is_term);
1090 "Force selection to be given entry, disallow no match", NULL,
1092 print_help_msg(
"-no-custom",
"",
"Don't accept custom entry, allow no match",
1094 print_help_msg(
"-select",
"[string]",
"Select the first row that matches",
1097 "Do not show what the user inputs. Show '*' instead.", NULL,
1100 "Allow and render pango markup as input data.", NULL, is_term);
1101 print_help_msg(
"-sep",
"[char]",
"Element separator.",
"'\\n'", is_term);
1103 "Read input from file instead from standard input.", NULL,
1106 "Force dmenu to first read all input data, then show dialog.",
1108 print_help_msg(
"-w",
"windowid",
"Position over window with X11 windowid.",
1110 print_help_msg(
"-keep-right",
"",
"Set ellipsize to end.", NULL, is_term);
1111 print_help_msg(
"-display-columns",
"",
"Only show the selected columns", NULL,
1114 "Separator to use to split columns (regex)", NULL, is_term);
1116 "When multi-select is enabled prefix this string when element "
1120 "When multi-select is enabled prefix this string when element "
1124 "Set ellipsize mode(start | middle | end).", NULL, is_term);
guint display_scale(void)
void print_help_msg(const char *option, const char *type, const char *text, const char *def, int isatty)
void parse_ranges(char *input, rofi_range_pair **list, unsigned int *length)
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
int find_arg_char(const char *const key, char *val)
void helper_tokenize_free(rofi_int_matcher **tokens)
void rofi_output_formatted_line(const char *format, const char *string, int selected_line, const char *filter)
char * rofi_expand_path(const char *input)
int find_arg_str(const char *const key, char **val)
int parse_case_sensitivity(const char *input)
int find_arg_uint(const char *const key, unsigned int *val)
int find_arg(const char *const key)
int helper_token_match(rofi_int_matcher *const *tokens, const char *input)
char * rofi_force_utf8(const gchar *data, ssize_t length)
gboolean rofi_icon_fetcher_get_ex(const uint32_t uid, cairo_surface_t **surface)
uint32_t rofi_icon_fetcher_query(const char *name, const int size)
void mode_destroy(Mode *mode)
int mode_init(Mode *mode)
void * mode_get_private_data(const Mode *mode)
void mode_set_private_data(Mode *mode, void *pd)
void rofi_set_return_code(int code)
void rofi_view_set_overlay(RofiViewState *state, const char *text)
Mode * rofi_view_get_mode(RofiViewState *state)
void rofi_view_reload(void)
int rofi_view_error_dialog(const char *msg, int markup)
void rofi_view_set_active(RofiViewState *state)
RofiViewState * rofi_view_get_active(void)
void rofi_view_restart(RofiViewState *state)
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
const char * rofi_view_get_user_input(const RofiViewState *state)
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
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_ellipsize_listview(RofiViewState *state, PangoEllipsizeMode mode)
struct rofi_int_matcher_t rofi_int_matcher
void dmenuscript_parse_entry_extras(G_GNUC_UNUSED Mode *sw, DmenuScriptEntry *entry, char *buffer, G_GNUC_UNUSED size_t length)
#define DEFAULT_MENU_LINES
DmenuModePrivateData * pd
DmenuScriptEntry values[BLOCK_LINES_SIZE]
unsigned int case_sensitive
ThemeWidget * rofi_theme_find_or_create_name(ThemeWidget *base, const char *name)
Property * rofi_theme_property_create(PropertyType type)
void rofi_theme_property_free(Property *p)
void rofi_theme_widget_add_properties(ThemeWidget *wid, GHashTable *table)