29#define G_LOG_DOMAIN "Modes.DMenu"
44#include <gio/gunixinputstream.h>
60static cairo_surface_t *
64static inline unsigned int bitget(uint32_t
const *
const array,
66 uint32_t bit = index % 32;
67 uint32_t val = array[index / 32];
68 return (val >> bit) & 1;
71static inline void bittoggle(uint32_t *
const array,
unsigned int index) {
72 uint32_t bit = index % 32;
73 uint32_t *v = &array[index / 32];
119#define BLOCK_LINES_SIZE 2048
129 if ((*block) == NULL) {
130 (*block) = g_malloc0(
sizeof(
Block));
132 (*block)->length = 0;
134 gsize data_len = len;
137 (*block)->values[(*block)->length].icon_fetch_size = 0;
138 (*block)->values[(*block)->length].icon_name = NULL;
139 (*block)->values[(*block)->length].meta = NULL;
140 (*block)->values[(*block)->length].info = NULL;
141 (*block)->values[(*block)->length].nonselectable = FALSE;
142 (*block)->values[(*block)->length].permanent = FALSE;
144 while (end < data + len && *end !=
'\0') {
147 if (end != data + len) {
148 data_len = end - data;
150 end + 1, len - data_len);
153 (*block)->values[(*block)->length].entry = utfstr;
154 (*block)->values[(*block)->length + 1].entry = NULL;
160 gsize data_len = len;
177 while (end < data + len && *end !=
'\0') {
180 if (end != data + len) {
181 data_len = end - data;
183 end + 1, len - data_len);
202 gpointer user_data) {
206 if ((condition & G_IO_IN) != G_IO_IN) {
207 return G_SOURCE_CONTINUE;
210 if (read(fd, &command, 1) == 1) {
211 if (command ==
'r') {
213 gboolean changed = FALSE;
216 while ((block = g_async_queue_try_pop(pd->
async_queue)) != NULL) {
232 }
else if (command ==
'q') {
238 return G_SOURCE_CONTINUE;
245 while (pre_read > 0 &&
264 GTimer *tim = g_timer_new();
270 struct timeval tv = {.tv_sec = 0, .tv_usec = 250000};
274 FD_SET(pd->
pipefd[0], &rfds);
276 int retval = select(MAX(fd, pd->
pipefd[0]) + 1, &rfds, NULL, NULL, &tv);
278 g_warning(
"select failed, giving up.");
282 if (FD_ISSET(pd->
pipefd[0], &rfds)) {
286 if (FD_ISSET(fd, &rfds)) {
287 ssize_t readbytes = 0;
288 if ((nread + 1024) > len) {
289 line = g_realloc(line, (nread + 1024));
292 readbytes = read(fd, &line[nread], 1023);
301 memmove(&line[0], &line[i + 1], nread - (i + 1));
305 double elapsed = g_timer_elapsed(tim, NULL);
347 g_timer_destroy(tim);
362 const unsigned int index,
363 gboolean multi_select) {
372 return g_strdup(input);
378 for (; splitted && splitted[ns]; ns++) {
381 GString *str_retv = g_string_new(
"");
391 unsigned int col_index =
392 (
unsigned int)g_ascii_strtoull(pd->
columns[i], NULL, 10);
393 if (col_index <= ns && col_index > 0) {
395 g_string_append(str_retv, splitted[col_index - 1]);
397 g_string_append_c(str_retv,
'\t');
398 g_string_append(str_retv, splitted[col_index - 1]);
402 g_strfreev(splitted);
403 retv = str_retv->str;
404 g_string_free(str_retv, FALSE);
408static inline unsigned int get_index(
unsigned int length,
int index) {
412 if (((
unsigned int)-index) <= length) {
413 return length + index;
423 if (retv[index].display) {
431 G_GNUC_UNUSED GList **list,
int get_entry) {
439 if (index >= start && index <= stop) {
447 if (index >= start && index <= stop) {
463 char *my_retv = NULL;
464 if (retv[index].display) {
505 .cfg_name_key =
"display-combi",
514 ._preprocess_input = NULL,
516 .private_data = NULL,
518 .display_name =
"dmenu",
538 if (
find_arg(
"-multi-select") >= 0) {
575 p->
name = g_strdup(
"lines");
579 g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
582 g_hash_table_replace(table, p->
name, p);
584 g_hash_table_destroy(table);
606 pd->
fd = STDIN_FILENO;
609 pd->
fd = open(str, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
611 char *msg = g_markup_printf_escaped(
612 "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
622 if (pipe(pd->
pipefd) == -1) {
623 g_error(
"Failed to create pipe");
626 g_error(
"Failed to create pipe");
642 char *msg = g_markup_printf_escaped(
643 "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
655 gchar *columns = NULL;
657 pd->
columns = g_strsplit(columns,
",", 0);
665 unsigned int index) {
677 pango_parse_markup(rmpd->
cmd_list[index].
entry, -1, 0, NULL, &esc, NULL,
686 for (
int j = 0; match && tokens[j] != NULL; j++) {
690 if (test == tokens[j]->invert && rmpd->
cmd_list[index].
meta) {
714 unsigned int selected_line,
715 unsigned int height) {
718 g_return_val_if_fail(pd->
cmd_list != NULL, NULL);
739 write(pd->
pipefd[1],
"q", 1);
745 while ((block = g_async_queue_try_pop_unlocked(pd->
async_queue)) != NULL) {
761 }
else if (retv >= 10) {
783 const char *cmd = input;
816 restart = (
find_arg(
"-only-match") >= 0);
935 if (
find_arg(
"-markup-rows") >= 0) {
940 if (cmd_list_length == 0) {
956 if (select != NULL) {
959 for (i = 0; i < cmd_list_length; i++) {
971 for (i = 0; i < cmd_list_length; i++) {
989 char *ellipsize_mode = NULL;
990 if (
find_arg_str(
"-ellipsize-mode", &ellipsize_mode) >= 0) {
991 if (ellipsize_mode) {
992 if (g_ascii_strcasecmp(ellipsize_mode,
"start") == 0) {
994 }
else if (g_ascii_strcasecmp(ellipsize_mode,
"middle") == 0) {
996 }
else if (g_ascii_strcasecmp(ellipsize_mode,
"end") == 0) {
999 g_warning(
"Unrecognized ellipsize mode: '%s'", ellipsize_mode);
1013 int is_term = isatty(fileno(stdout));
1015 "-mesg",
"[string]",
1016 "Print a small user message under the prompt (uses pango markup)", NULL,
1018 print_help_msg(
"-p",
"[string]",
"Prompt to display left of entry field",
1020 print_help_msg(
"-selected-row",
"[integer]",
"Select row", NULL, is_term);
1021 print_help_msg(
"-format",
"[string]",
"Output format string",
"s", is_term);
1022 print_help_msg(
"-u",
"[list]",
"List of row indexes to mark urgent", NULL,
1024 print_help_msg(
"-a",
"[list]",
"List of row indexes to mark active", NULL,
1026 print_help_msg(
"-l",
"[integer] ",
"Number of rows to display", NULL,
1028 print_help_msg(
"-window-title",
"[string] ",
"Set the dmenu window title",
1030 print_help_msg(
"-i",
"",
"Set filter to be case insensitive", NULL, is_term);
1032 "Force selection to be given entry, disallow no match", NULL,
1034 print_help_msg(
"-no-custom",
"",
"Don't accept custom entry, allow no match",
1036 print_help_msg(
"-select",
"[string]",
"Select the first row that matches",
1039 "Do not show what the user inputs. Show '*' instead.", NULL,
1042 "Allow and render pango markup as input data.", NULL, is_term);
1043 print_help_msg(
"-sep",
"[char]",
"Element separator.",
"'\\n'", is_term);
1045 "Read input from file instead from standard input.", NULL,
1048 "Force dmenu to first read all input data, then show dialog.",
1050 print_help_msg(
"-w",
"windowid",
"Position over window with X11 windowid.",
1052 print_help_msg(
"-keep-right",
"",
"Set ellipsize to end.", NULL, is_term);
1053 print_help_msg(
"-display-columns",
"",
"Only show the selected columns", NULL,
1056 "Separator to use to split columns (regex)", NULL, is_term);
1058 "When multi-select is enabled prefix this string when element "
1062 "When multi-select is enabled prefix this string when element "
1066 "Set ellipsize mode(start | middle | end).", NULL, is_term);
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 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)
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)