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;
138 (*block)->values[(*block)->length].icon_fetch_size = 0;
139 (*block)->values[(*block)->length].icon_fetch_scale = 0;
140 (*block)->values[(*block)->length].icon_name = NULL;
141 (*block)->values[(*block)->length].meta = NULL;
142 (*block)->values[(*block)->length].info = NULL;
143 (*block)->values[(*block)->length].nonselectable = FALSE;
144 (*block)->values[(*block)->length].permanent = FALSE;
146 while (end < data + len && *end !=
'\0') {
149 if (end != data + len) {
150 data_len = end - data;
152 end + 1, len - data_len);
155 (*block)->values[(*block)->length].entry = utfstr;
156 (*block)->values[(*block)->length + 1].entry = NULL;
162 gsize data_len = len;
180 while (end < data + len && *end !=
'\0') {
183 if (end != data + len) {
184 data_len = end - data;
186 end + 1, len - data_len);
205 gpointer user_data) {
209 if ((condition & G_IO_IN) != G_IO_IN) {
210 return G_SOURCE_CONTINUE;
213 if (read(fd, &command, 1) == 1) {
214 if (command ==
'r') {
216 gboolean changed = FALSE;
219 while ((block = g_async_queue_try_pop(pd->
async_queue)) != NULL) {
235 }
else if (command ==
'q') {
241 return G_SOURCE_CONTINUE;
248 while (pre_read > 0 &&
267 GTimer *tim = g_timer_new();
273 struct timeval tv = {.tv_sec = 0, .tv_usec = 250000};
277 FD_SET(pd->
pipefd[0], &rfds);
279 int retval = select(MAX(fd, pd->
pipefd[0]) + 1, &rfds, NULL, NULL, &tv);
281 g_warning(
"select failed, giving up.");
285 if (FD_ISSET(pd->
pipefd[0], &rfds)) {
289 if (FD_ISSET(fd, &rfds)) {
290 ssize_t readbytes = 0;
291 if ((nread + 1024) > len) {
292 line = g_realloc(line, (len + 2048));
295 readbytes = read(fd, &line[nread], 1023);
304 memmove(&line[0], &line[i + 1], nread - (i + 1));
308 double elapsed = g_timer_elapsed(tim, NULL);
350 g_timer_destroy(tim);
365 const unsigned int index,
366 gboolean multi_select) {
375 return g_strdup(input);
381 for (; splitted && splitted[ns]; ns++) {
384 GString *str_retv = g_string_new(
"");
394 unsigned int col_index =
395 (
unsigned int)g_ascii_strtoull(pd->
columns[i], NULL, 10);
396 if (col_index <= ns && col_index > 0) {
398 g_string_append(str_retv, splitted[col_index - 1]);
400 g_string_append_c(str_retv,
'\t');
401 g_string_append(str_retv, splitted[col_index - 1]);
405 g_strfreev(splitted);
406 retv = str_retv->str;
407 g_string_free(str_retv, FALSE);
411static inline unsigned int get_index(
unsigned int length,
int index) {
415 if (((
unsigned int)-index) <= length) {
416 return length + index;
426 if (retv[index].display) {
434 G_GNUC_UNUSED GList **list,
int get_entry) {
442 if (index >= start && index <= stop) {
450 if (index >= start && index <= stop) {
466 char *my_retv = NULL;
467 if (retv[index].display) {
508 .cfg_name_key =
"display-combi",
517 ._preprocess_input = NULL,
519 .private_data = NULL,
521 .display_name =
"dmenu",
541 if (
find_arg(
"-multi-select") >= 0) {
578 p->
name = g_strdup(
"lines");
582 g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
585 g_hash_table_replace(table, p->
name, p);
587 g_hash_table_destroy(table);
604 config.case_sensitive = TRUE;
606 config.case_sensitive = FALSE;
609 pd->
fd = STDIN_FILENO;
612 pd->
fd = open(str, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
614 char *msg = g_markup_printf_escaped(
615 "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
625 if (pipe(pd->
pipefd) == -1) {
626 g_error(
"Failed to create pipe");
629 g_error(
"Failed to create pipe");
645 char *msg = g_markup_printf_escaped(
646 "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
658 gchar *columns = NULL;
660 pd->
columns = g_strsplit(columns,
",", 0);
668 unsigned int index) {
680 pango_parse_markup(rmpd->
cmd_list[index].
entry, -1, 0, NULL, &esc, NULL,
689 for (
int j = 0; match && tokens[j] != NULL; j++) {
693 if (test == tokens[j]->invert && rmpd->
cmd_list[index].
meta) {
717 unsigned int selected_line,
718 unsigned int height) {
722 g_return_val_if_fail(pd->
cmd_list != NULL, NULL);
744 write(pd->
pipefd[1],
"q", 1);
750 while ((block = g_async_queue_try_pop_unlocked(pd->
async_queue)) != NULL) {
766 }
else if (retv >= 10) {
788 const char *cmd = input;
821 restart = (
find_arg(
"-only-match") >= 0);
940 if (
find_arg(
"-markup-rows") >= 0) {
945 if (cmd_list_length == 0) {
949 if (
config.auto_select && cmd_list_length == 1) {
957 input = g_strdup(
config.filter);
961 if (select != NULL) {
965 for (i = 0; i < cmd_list_length; i++) {
978 for (i = 0; i < cmd_list_length; i++) {
996 char *ellipsize_mode = NULL;
997 if (
find_arg_str(
"-ellipsize-mode", &ellipsize_mode) >= 0) {
998 if (ellipsize_mode) {
999 if (g_ascii_strcasecmp(ellipsize_mode,
"start") == 0) {
1001 }
else if (g_ascii_strcasecmp(ellipsize_mode,
"middle") == 0) {
1003 }
else if (g_ascii_strcasecmp(ellipsize_mode,
"end") == 0) {
1006 g_warning(
"Unrecognized ellipsize mode: '%s'", ellipsize_mode);
1020 int is_term = isatty(fileno(stdout));
1022 "-mesg",
"[string]",
1023 "Print a small user message under the prompt (uses pango markup)", NULL,
1025 print_help_msg(
"-p",
"[string]",
"Prompt to display left of entry field",
1027 print_help_msg(
"-selected-row",
"[integer]",
"Select row", NULL, is_term);
1028 print_help_msg(
"-format",
"[string]",
"Output format string",
"s", is_term);
1029 print_help_msg(
"-u",
"[list]",
"List of row indexes to mark urgent", NULL,
1031 print_help_msg(
"-a",
"[list]",
"List of row indexes to mark active", NULL,
1033 print_help_msg(
"-l",
"[integer] ",
"Number of rows to display", NULL,
1035 print_help_msg(
"-window-title",
"[string] ",
"Set the dmenu window title",
1037 print_help_msg(
"-i",
"",
"Set filter to be case insensitive", NULL, is_term);
1039 "Force selection to be given entry, disallow no match", NULL,
1041 print_help_msg(
"-no-custom",
"",
"Don't accept custom entry, allow no match",
1043 print_help_msg(
"-select",
"[string]",
"Select the first row that matches",
1046 "Do not show what the user inputs. Show '*' instead.", NULL,
1049 "Allow and render pango markup as input data.", NULL, is_term);
1050 print_help_msg(
"-sep",
"[char]",
"Element separator.",
"'\\n'", is_term);
1052 "Read input from file instead from standard input.", NULL,
1055 "Force dmenu to first read all input data, then show dialog.",
1057 print_help_msg(
"-w",
"windowid",
"Position over window with X11 windowid.",
1059 print_help_msg(
"-keep-right",
"",
"Set ellipsize to end.", NULL, is_term);
1060 print_help_msg(
"-display-columns",
"",
"Only show the selected columns", NULL,
1063 "Separator to use to split columns (regex)", NULL, is_term);
1065 "When multi-select is enabled prefix this string when element "
1069 "When multi-select is enabled prefix this string when element "
1073 "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)
cairo_surface_t * rofi_icon_fetcher_get(const uint32_t uid)
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]
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)