rofi  1.7.0
dmenu.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2021 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 "Dialogs.DMenu"
30 
31 #include "dialogs/dmenu.h"
32 #include "helper.h"
33 #include "rofi-icon-fetcher.h"
34 #include "rofi.h"
35 #include "settings.h"
36 #include "view.h"
37 #include "widgets/textbox.h"
38 #include "xrmoptions.h"
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <gio/gio.h>
43 #include <gio/gunixinputstream.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <unistd.h>
52 
54 
55 static int dmenu_mode_init(Mode *sw);
56 static int dmenu_token_match(const Mode *sw, rofi_int_matcher **tokens,
57  unsigned int index);
58 static cairo_surface_t *dmenu_get_icon(const Mode *sw,
59  unsigned int selected_line, int height);
60 static char *dmenu_get_message(const Mode *sw);
61 
62 static inline unsigned int bitget(uint32_t *array, unsigned int index) {
63  uint32_t bit = index % 32;
64  uint32_t val = array[index / 32];
65  return (val >> bit) & 1;
66 }
67 
68 static inline void bittoggle(uint32_t *array, unsigned int index) {
69  uint32_t bit = index % 32;
70  uint32_t *v = &array[index / 32];
71  *v ^= 1 << bit;
72 }
73 
74 typedef struct {
76  // Separator.
77  char separator;
78 
79  unsigned int selected_line;
80  char *message;
81  char *format;
83  unsigned int num_urgent_list;
85  unsigned int num_active_list;
86  uint32_t *selected_list;
87  unsigned int num_selected_list;
88  unsigned int do_markup;
89  // List with entries.
91  unsigned int cmd_list_real_length;
92  unsigned int cmd_list_length;
93  unsigned int only_selected;
94  unsigned int selected_count;
95 
96  gchar **columns;
98  gboolean multi_select;
99 
100  GCancellable *cancel;
102  GInputStream *input_stream;
103  GDataInputStream *data_input_stream;
105 
106 static void async_close_callback(GObject *source_object, GAsyncResult *res,
107  G_GNUC_UNUSED gpointer user_data) {
108  g_input_stream_close_finish(G_INPUT_STREAM(source_object), res, NULL);
109  g_debug("Closing data stream.");
110 }
111 
112 static void read_add(DmenuModePrivateData *pd, char *data, gsize len) {
113  gsize data_len = len;
114  if ((pd->cmd_list_length + 2) > pd->cmd_list_real_length) {
115  pd->cmd_list_real_length = MAX(pd->cmd_list_real_length * 2, 512);
116  pd->cmd_list = g_realloc(pd->cmd_list, (pd->cmd_list_real_length) *
117  sizeof(DmenuScriptEntry));
118  }
119  // Init.
121  pd->cmd_list[pd->cmd_list_length].icon_name = NULL;
122  pd->cmd_list[pd->cmd_list_length].meta = NULL;
123  pd->cmd_list[pd->cmd_list_length].info = NULL;
124  char *end = data;
125  while (end < data + len && *end != '\0') {
126  end++;
127  }
128  if (end != data + len) {
129  data_len = end - data;
131  end + 1, len - data_len);
132  }
133  char *utfstr = rofi_force_utf8(data, data_len);
134  pd->cmd_list[pd->cmd_list_length].entry = utfstr;
135  pd->cmd_list[pd->cmd_list_length + 1].entry = NULL;
136 
137  pd->cmd_list_length++;
138 }
139 static void async_read_callback(GObject *source_object, GAsyncResult *res,
140  gpointer user_data) {
141  GDataInputStream *stream = (GDataInputStream *)source_object;
142  DmenuModePrivateData *pd = (DmenuModePrivateData *)user_data;
143  gsize len;
144  char *data = g_data_input_stream_read_upto_finish(stream, res, &len, NULL);
145  if (data != NULL) {
146  // Absorb separator, already in buffer so should not block.
147  g_data_input_stream_read_byte(stream, NULL, NULL);
148  read_add(pd, data, len);
149  g_free(data);
151 
152  g_data_input_stream_read_upto_async(pd->data_input_stream, &(pd->separator),
153  1, G_PRIORITY_LOW, pd->cancel,
154  async_read_callback, pd);
155  return;
156  } else {
157  GError *error = NULL;
158  // Absorb separator, already in buffer so should not block.
159  // If error == NULL end of stream..
160  g_data_input_stream_read_byte(stream, NULL, &error);
161  if (error == NULL) {
162  // Add empty line.
163  read_add(pd, "", 0);
165 
166  g_data_input_stream_read_upto_async(pd->data_input_stream,
167  &(pd->separator), 1, G_PRIORITY_LOW,
168  pd->cancel, async_read_callback, pd);
169  return;
170  }
171  g_error_free(error);
172  }
173  if (!g_cancellable_is_cancelled(pd->cancel)) {
174  // Hack, don't use get active.
175  g_debug("Clearing overlay");
177  g_input_stream_close_async(G_INPUT_STREAM(stream), G_PRIORITY_LOW,
178  pd->cancel, async_close_callback, pd);
179  }
180 }
181 
182 static void async_read_cancel(G_GNUC_UNUSED GCancellable *cancel,
183  G_GNUC_UNUSED gpointer data) {
184  g_debug("Cancelled the async read.");
185 }
186 
187 static int get_dmenu_async(DmenuModePrivateData *pd, int sync_pre_read) {
188  while (sync_pre_read--) {
189  gsize len = 0;
190  char *data = g_data_input_stream_read_upto(
191  pd->data_input_stream, &(pd->separator), 1, &len, NULL, NULL);
192  if (data == NULL) {
193  g_input_stream_close_async(G_INPUT_STREAM(pd->input_stream),
194  G_PRIORITY_LOW, pd->cancel,
196  return FALSE;
197  }
198  g_data_input_stream_read_byte(pd->data_input_stream, NULL, NULL);
199  read_add(pd, data, len);
200  g_free(data);
201  }
202  g_data_input_stream_read_upto_async(pd->data_input_stream, &(pd->separator),
203  1, G_PRIORITY_LOW, pd->cancel,
204  async_read_callback, pd);
205  return TRUE;
206 }
208  while (TRUE) {
209  gsize len = 0;
210  char *data = g_data_input_stream_read_upto(
211  pd->data_input_stream, &(pd->separator), 1, &len, NULL, NULL);
212  if (data == NULL) {
213  break;
214  }
215  g_data_input_stream_read_byte(pd->data_input_stream, NULL, NULL);
216  read_add(pd, data, len);
217  g_free(data);
218  }
219  g_input_stream_close_async(G_INPUT_STREAM(pd->input_stream), G_PRIORITY_LOW,
220  pd->cancel, async_close_callback, pd);
221 }
222 
223 static unsigned int dmenu_mode_get_num_entries(const Mode *sw) {
224  const DmenuModePrivateData *rmpd =
226  return rmpd->cmd_list_length;
227 }
228 
230  const char *input) {
231  if (pd->columns == NULL) {
232  return g_strdup(input);
233  }
234  char *retv = NULL;
235  char **splitted =
236  g_regex_split_simple(pd->column_separator, input, G_REGEX_CASELESS, 00);
237  uint32_t ns = 0;
238  for (; splitted && splitted[ns]; ns++) {
239  ;
240  }
241  for (uint32_t i = 0; pd->columns && pd->columns[i]; i++) {
242  unsigned int index =
243  (unsigned int)g_ascii_strtoull(pd->columns[i], NULL, 10);
244  if (index < ns && index > 0) {
245  if (retv == NULL) {
246  retv = g_strdup(splitted[index - 1]);
247  } else {
248  gchar *t = g_strjoin("\t", retv, splitted[index - 1], NULL);
249  g_free(retv);
250  retv = t;
251  }
252  }
253  }
254  g_strfreev(splitted);
255  return retv ? retv : g_strdup("");
256 }
257 
258 static inline unsigned int get_index(unsigned int length, int index) {
259  if (index >= 0) {
260  return index;
261  }
262  if (((unsigned int)-index) <= length) {
263  return length + index;
264  }
265  // Out of range.
266  return UINT_MAX;
267 }
268 
269 static char *get_display_data(const Mode *data, unsigned int index, int *state,
270  G_GNUC_UNUSED GList **list, int get_entry) {
271  Mode *sw = (Mode *)data;
274  for (unsigned int i = 0; i < pd->num_active_list; i++) {
275  unsigned int start =
277  unsigned int stop = get_index(pd->cmd_list_length, pd->active_list[i].stop);
278  if (index >= start && index <= stop) {
279  *state |= ACTIVE;
280  }
281  }
282  for (unsigned int i = 0; i < pd->num_urgent_list; i++) {
283  unsigned int start =
285  unsigned int stop = get_index(pd->cmd_list_length, pd->urgent_list[i].stop);
286  if (index >= start && index <= stop) {
287  *state |= URGENT;
288  }
289  }
290  if (pd->selected_list && bitget(pd->selected_list, index) == TRUE) {
291  *state |= SELECTED;
292  }
293  if (pd->do_markup) {
294  *state |= MARKUP;
295  }
296  return get_entry ? dmenu_format_output_string(pd, retv[index].entry) : NULL;
297 }
298 
299 static void dmenu_mode_free(Mode *sw) {
300  if (mode_get_private_data(sw) == NULL) {
301  return;
302  }
304  if (pd != NULL) {
305  if (pd->cancel) {
306  // If open, cancel reads.
307  if (pd->input_stream && !g_input_stream_is_closed(pd->input_stream)) {
308  g_cancellable_cancel(pd->cancel);
309  }
310  // This blocks until cancel is done.
311  g_cancellable_disconnect(pd->cancel, pd->cancel_source);
312  if (pd->input_stream) {
313  // Should close the stream if not yet done.
314  g_object_unref(pd->data_input_stream);
315  g_object_unref(pd->input_stream);
316  }
317  g_object_unref(pd->cancel);
318  }
319 
320  for (size_t i = 0; i < pd->cmd_list_length; i++) {
321  if (pd->cmd_list[i].entry) {
322  g_free(pd->cmd_list[i].entry);
323  g_free(pd->cmd_list[i].icon_name);
324  g_free(pd->cmd_list[i].meta);
325  g_free(pd->cmd_list[i].info);
326  }
327  }
328  g_free(pd->cmd_list);
329  g_free(pd->urgent_list);
330  g_free(pd->active_list);
331  g_free(pd->selected_list);
332 
333  g_free(pd);
334  mode_set_private_data(sw, NULL);
335  }
336 }
337 
338 #include "mode-private.h"
340 Mode dmenu_mode = {.name = "dmenu",
341  .cfg_name_key = "display-combi",
342  ._init = dmenu_mode_init,
343  ._get_num_entries = dmenu_mode_get_num_entries,
344  ._result = NULL,
345  ._destroy = dmenu_mode_free,
346  ._token_match = dmenu_token_match,
347  ._get_display_value = get_display_data,
348  ._get_icon = dmenu_get_icon,
349  ._get_completion = NULL,
350  ._preprocess_input = NULL,
351  ._get_message = dmenu_get_message,
352  .private_data = NULL,
353  .free = NULL,
354  .display_name = "dmenu"};
355 
356 static int dmenu_mode_init(Mode *sw) {
357  if (mode_get_private_data(sw) != NULL) {
358  return TRUE;
359  }
360  mode_set_private_data(sw, g_malloc0(sizeof(DmenuModePrivateData)));
362 
363  pd->separator = '\n';
364  pd->selected_line = UINT32_MAX;
365 
366  find_arg_str("-mesg", &(pd->message));
367 
368  // Input data separator.
369  find_arg_char("-sep", &(pd->separator));
370 
371  find_arg_uint("-selected-row", &(pd->selected_line));
372  // By default we print the unescaped line back.
373  pd->format = "s";
374 
375  // Allow user to override the output format.
376  find_arg_str("-format", &(pd->format));
377  // Urgent.
378  char *str = NULL;
379  find_arg_str("-u", &str);
380  if (str != NULL) {
381  parse_ranges(str, &(pd->urgent_list), &(pd->num_urgent_list));
382  }
383  // Active
384  str = NULL;
385  find_arg_str("-a", &str);
386  if (str != NULL) {
387  parse_ranges(str, &(pd->active_list), &(pd->num_active_list));
388  }
389 
390  // DMENU COMPATIBILITY
391  unsigned int lines = DEFAULT_MENU_LINES;
392  find_arg_uint("-l", &(lines));
393  if (lines != DEFAULT_MENU_LINES) {
395  p->name = g_strdup("lines");
396  p->value.i = lines;
399  GHashTable *table =
400  g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
401  (GDestroyNotify)rofi_theme_property_free);
402 
403  g_hash_table_replace(table, p->name, p);
405  g_hash_table_destroy(table);
406  }
407 
408  str = NULL;
409  find_arg_str("-window-title", &str);
410  if (str) {
411  dmenu_mode.display_name = str;
412  }
413 
418  if (find_arg("-b") >= 0) {
419  config.location = 6;
420  }
421  /* -i case insensitive */
422  config.case_sensitive = TRUE;
423  if (find_arg("-i") >= 0) {
424  config.case_sensitive = FALSE;
425  }
426  int fd = STDIN_FILENO;
427  str = NULL;
428  if (find_arg_str("-input", &str)) {
429  char *estr = rofi_expand_path(str);
430  fd = open(str, O_RDONLY);
431  if (fd < 0) {
432  char *msg = g_markup_printf_escaped(
433  "Failed to open file: <b>%s</b>:\n\t<i>%s</i>", estr,
434  g_strerror(errno));
435  rofi_view_error_dialog(msg, TRUE);
436  g_free(msg);
437  g_free(estr);
438  return TRUE;
439  }
440  g_free(estr);
441  }
442  // If input is stdin, and a tty, do not read as rofi grabs input and therefore
443  // blocks.
444  if (!(fd == STDIN_FILENO && isatty(fd) == 1)) {
445  pd->cancel = g_cancellable_new();
446  pd->cancel_source = g_cancellable_connect(
447  pd->cancel, G_CALLBACK(async_read_cancel), pd, NULL);
448  pd->input_stream = g_unix_input_stream_new(fd, fd != STDIN_FILENO);
449  pd->data_input_stream = g_data_input_stream_new(pd->input_stream);
450  }
451  gchar *columns = NULL;
452  if (find_arg_str("-display-columns", &columns)) {
453  pd->columns = g_strsplit(columns, ",", 0);
454  pd->column_separator = "\t";
455  find_arg_str("-display-column-separator", &pd->column_separator);
456  }
457  return TRUE;
458 }
459 
460 static int dmenu_token_match(const Mode *sw, rofi_int_matcher **tokens,
461  unsigned int index) {
462  DmenuModePrivateData *rmpd =
465  char *esc = NULL;
466  if (rmpd->do_markup) {
467  pango_parse_markup(rmpd->cmd_list[index].entry, -1, 0, NULL, &esc, NULL,
468  NULL);
469  } else {
470  esc = rmpd->cmd_list[index].entry;
471  }
472  if (esc) {
473  // int retv = helper_token_match ( tokens, esc );
474  int match = 1;
475  if (tokens) {
476  for (int j = 0; match && tokens != NULL && tokens[j] != NULL; j++) {
477  rofi_int_matcher *ftokens[2] = {tokens[j], NULL};
478  int test = 0;
479  test = helper_token_match(ftokens, esc);
480  if (test == tokens[j]->invert && rmpd->cmd_list[index].meta) {
481  test = helper_token_match(ftokens, rmpd->cmd_list[index].meta);
482  }
483 
484  if (test == 0) {
485  match = 0;
486  }
487  }
488  }
489  if (rmpd->do_markup) {
490  g_free(esc);
491  }
492  return match;
493  }
494  return FALSE;
495 }
496 static char *dmenu_get_message(const Mode *sw) {
498  if (pd->message) {
499  return g_strdup(pd->message);
500  }
501  return NULL;
502 }
503 static cairo_surface_t *dmenu_get_icon(const Mode *sw,
504  unsigned int selected_line, int height) {
506  g_return_val_if_fail(pd->cmd_list != NULL, NULL);
507  DmenuScriptEntry *dr = &(pd->cmd_list[selected_line]);
508  if (dr->icon_name == NULL) {
509  return NULL;
510  }
511  if (dr->icon_fetch_uid > 0) {
513  }
516 }
517 
518 static void dmenu_finish(RofiViewState *state, int retv) {
519  if (retv == FALSE) {
520  rofi_set_return_code(EXIT_FAILURE);
521  } else if (retv >= 10) {
522  rofi_set_return_code(retv);
523  } else {
524  rofi_set_return_code(EXIT_SUCCESS);
525  }
526  rofi_view_set_active(NULL);
527  rofi_view_free(state);
529 }
530 
531 static void dmenu_print_results(DmenuModePrivateData *pd, const char *input) {
532  DmenuScriptEntry *cmd_list = pd->cmd_list;
533  int seen = FALSE;
534  if (pd->selected_list != NULL) {
535  for (unsigned int st = 0; st < pd->cmd_list_length; st++) {
536  if (bitget(pd->selected_list, st)) {
537  seen = TRUE;
538  rofi_output_formatted_line(pd->format, cmd_list[st].entry, st, input);
539  }
540  }
541  }
542  if (!seen) {
543  const char *cmd = input;
544  if (pd->selected_line != UINT32_MAX) {
545  cmd = cmd_list[pd->selected_line].entry;
546  }
547  rofi_output_formatted_line(pd->format, cmd, pd->selected_line, input);
548  }
549 }
550 
551 static void dmenu_finalize(RofiViewState *state) {
552  int retv = FALSE;
555  unsigned int cmd_list_length = pd->cmd_list_length;
556  DmenuScriptEntry *cmd_list = pd->cmd_list;
557 
558  char *input = g_strdup(rofi_view_get_user_input(state));
560  ;
561  MenuReturn mretv = rofi_view_get_return_value(state);
562  unsigned int next_pos = rofi_view_get_next_position(state);
563  int restart = 0;
564  // Special behavior.
565  if (pd->only_selected) {
569  restart = 1;
570  // Skip if no valid item is selected.
571  if ((mretv & MENU_CANCEL) == MENU_CANCEL) {
572  // In no custom mode we allow canceling.
573  restart = (find_arg("-only-match") >= 0);
574  } else if (pd->selected_line != UINT32_MAX) {
575  if ((mretv & MENU_CUSTOM_ACTION) && pd->multi_select) {
576  restart = TRUE;
577  if (pd->selected_list == NULL) {
578  pd->selected_list =
579  g_malloc0(sizeof(uint32_t) * (pd->cmd_list_length / 32 + 1));
580  }
581  pd->selected_count +=
582  (bitget(pd->selected_list, pd->selected_line) ? (-1) : (1));
584  // Move to next line.
585  pd->selected_line = MIN(next_pos, cmd_list_length - 1);
586  if (pd->selected_count > 0) {
587  char *str =
588  g_strdup_printf("%u/%u", pd->selected_count, pd->cmd_list_length);
589  rofi_view_set_overlay(state, str);
590  g_free(str);
591  } else {
592  rofi_view_set_overlay(state, NULL);
593  }
594  } else if ((mretv & (MENU_OK | MENU_CUSTOM_COMMAND)) &&
595  cmd_list[pd->selected_line].entry != NULL) {
596  if (cmd_list[pd->selected_line].nonselectable == TRUE) {
597  g_free(input);
598  return;
599  }
600  dmenu_print_results(pd, input);
601  retv = TRUE;
602  if ((mretv & MENU_CUSTOM_COMMAND)) {
603  retv = 10 + (mretv & MENU_LOWER_MASK);
604  }
605  g_free(input);
606  dmenu_finish(state, retv);
607  return;
608  } else {
609  pd->selected_line = next_pos - 1;
610  }
611  }
612  // Restart
613  rofi_view_restart(state);
615  if (!restart) {
616  dmenu_finish(state, retv);
617  }
618  return;
619  }
620  // We normally do not want to restart the loop.
621  restart = FALSE;
622  // Normal mode
623  if ((mretv & MENU_OK) && pd->selected_line != UINT32_MAX &&
624  cmd_list[pd->selected_line].entry != NULL) {
625  // Check if entry is non-selectable.
626  if (cmd_list[pd->selected_line].nonselectable == TRUE) {
627  g_free(input);
628  return;
629  }
630  if ((mretv & MENU_CUSTOM_ACTION) && pd->multi_select) {
631  restart = TRUE;
632  if (pd->selected_list == NULL) {
633  pd->selected_list =
634  g_malloc0(sizeof(uint32_t) * (pd->cmd_list_length / 32 + 1));
635  }
636  pd->selected_count +=
637  (bitget(pd->selected_list, pd->selected_line) ? (-1) : (1));
639  // Move to next line.
640  pd->selected_line = MIN(next_pos, cmd_list_length - 1);
641  if (pd->selected_count > 0) {
642  char *str =
643  g_strdup_printf("%u/%u", pd->selected_count, pd->cmd_list_length);
644  rofi_view_set_overlay(state, str);
645  g_free(str);
646  } else {
647  rofi_view_set_overlay(state, NULL);
648  }
649  } else {
650  dmenu_print_results(pd, input);
651  }
652  retv = TRUE;
653  }
654  // Custom input
655  else if ((mretv & (MENU_CUSTOM_INPUT))) {
656  dmenu_print_results(pd, input);
657 
658  retv = TRUE;
659  }
660  // Quick switch with entry selected.
661  else if ((mretv & MENU_CUSTOM_COMMAND)) {
662  dmenu_print_results(pd, input);
663 
664  restart = FALSE;
665  retv = 10 + (mretv & MENU_LOWER_MASK);
666  }
667  g_free(input);
668  if (restart) {
669  rofi_view_restart(state);
671  } else {
672  dmenu_finish(state, retv);
673  }
674 }
675 
678  MenuFlags menu_flags = MENU_NORMAL;
680  int async = TRUE;
681 
682  // For now these only work in sync mode.
683  if (find_arg("-sync") >= 0 || find_arg("-dump") >= 0 ||
684  find_arg("-select") >= 0 || find_arg("-no-custom") >= 0 ||
685  find_arg("-only-match") >= 0 || config.auto_select ||
686  find_arg("-selected-row") >= 0) {
687  async = FALSE;
688  }
689 
690  // Check if the subsystem is setup for reading, otherwise do not read.
691  if (pd->cancel != NULL) {
692  if (async) {
693  unsigned int pre_read = 25;
694  find_arg_uint("-async-pre-read", &pre_read);
695  async = get_dmenu_async(pd, pre_read);
696  } else {
697  get_dmenu_sync(pd);
698  }
699  }
700  char *input = NULL;
701  unsigned int cmd_list_length = pd->cmd_list_length;
702  DmenuScriptEntry *cmd_list = pd->cmd_list;
703 
704  pd->only_selected = FALSE;
705  pd->multi_select = FALSE;
706  if (find_arg("-multi-select") >= 0) {
707  menu_flags = MENU_INDICATOR;
708  pd->multi_select = TRUE;
709  }
710  if (find_arg("-markup-rows") >= 0) {
711  pd->do_markup = TRUE;
712  }
713  if (find_arg("-only-match") >= 0 || find_arg("-no-custom") >= 0) {
714  pd->only_selected = TRUE;
715  if (cmd_list_length == 0) {
716  return TRUE;
717  }
718  }
719  if (config.auto_select && cmd_list_length == 1) {
720  rofi_output_formatted_line(pd->format, cmd_list[0].entry, 0, config.filter);
721  return TRUE;
722  }
723  if (find_arg("-password") >= 0) {
724  menu_flags |= MENU_PASSWORD;
725  }
726  /* copy filter string */
727  input = g_strdup(config.filter);
728 
729  char *select = NULL;
730  find_arg_str("-select", &select);
731  if (select != NULL) {
733  unsigned int i = 0;
734  for (i = 0; i < cmd_list_length; i++) {
735  if (helper_token_match(tokens, cmd_list[i].entry)) {
736  pd->selected_line = i;
737  break;
738  }
739  }
740  helper_tokenize_free(tokens);
741  }
742  if (find_arg("-dump") >= 0) {
745  unsigned int i = 0;
746  for (i = 0; i < cmd_list_length; i++) {
747  if (tokens == NULL || helper_token_match(tokens, cmd_list[i].entry)) {
748  rofi_output_formatted_line(pd->format, cmd_list[i].entry, i,
749  config.filter);
750  }
751  }
752  helper_tokenize_free(tokens);
754  g_free(input);
755  return TRUE;
756  }
758  RofiViewState *state =
759  rofi_view_create(&dmenu_mode, input, menu_flags, dmenu_finalize);
760 
761  if (find_arg("-keep-right") >= 0) {
763  }
764  // @TODO we should do this better.
765  if (async && (pd->cancel != NULL)) {
766  rofi_view_set_overlay(state, "Loading.. ");
767  }
769  rofi_view_set_active(state);
770 
771  return FALSE;
772 }
773 
775  int is_term = isatty(fileno(stdout));
777  "-mesg", "[string]",
778  "Print a small user message under the prompt (uses pango markup)", NULL,
779  is_term);
780  print_help_msg("-p", "[string]", "Prompt to display left of entry field",
781  NULL, is_term);
782  print_help_msg("-selected-row", "[integer]", "Select row", NULL, is_term);
783  print_help_msg("-format", "[string]", "Output format string", "s", is_term);
784  print_help_msg("-u", "[list]", "List of row indexes to mark urgent", NULL,
785  is_term);
786  print_help_msg("-a", "[list]", "List of row indexes to mark active", NULL,
787  is_term);
788  print_help_msg("-l", "[integer] ", "Number of rows to display", NULL,
789  is_term);
790  print_help_msg("-window-title", "[string] ", "Set the dmenu window title",
791  NULL, is_term);
792  print_help_msg("-i", "", "Set filter to be case insensitive", NULL, is_term);
793  print_help_msg("-only-match", "",
794  "Force selection to be given entry, disallow no match", NULL,
795  is_term);
796  print_help_msg("-no-custom", "", "Don't accept custom entry, allow no match",
797  NULL, is_term);
798  print_help_msg("-select", "[string]", "Select the first row that matches",
799  NULL, is_term);
800  print_help_msg("-password", "",
801  "Do not show what the user inputs. Show '*' instead.", NULL,
802  is_term);
803  print_help_msg("-markup-rows", "",
804  "Allow and render pango markup as input data.", NULL, is_term);
805  print_help_msg("-sep", "[char]", "Element separator.", "'\\n'", is_term);
806  print_help_msg("-input", "[filename]",
807  "Read input from file instead from standard input.", NULL,
808  is_term);
809  print_help_msg("-sync", "",
810  "Force dmenu to first read all input data, then show dialog.",
811  NULL, is_term);
812  print_help_msg("-async-pre-read", "[number]",
813  "Read several entries blocking before switching to async mode",
814  "25", is_term);
815  print_help_msg("-w", "windowid", "Position over window with X11 windowid.",
816  NULL, is_term);
817  print_help_msg("-keep-right", "", "Set ellipsize to end.", NULL, is_term);
818 }
static unsigned int bitget(uint32_t *array, unsigned int index)
Definition: dmenu.c:62
static void read_add(DmenuModePrivateData *pd, char *data, gsize len)
Definition: dmenu.c:112
static cairo_surface_t * dmenu_get_icon(const Mode *sw, unsigned int selected_line, int height)
Definition: dmenu.c:503
static void bittoggle(uint32_t *array, unsigned int index)
Definition: dmenu.c:68
Mode dmenu_mode
Definition: dmenu.c:340
static int dmenu_token_match(const Mode *sw, rofi_int_matcher **tokens, unsigned int index)
Definition: dmenu.c:460
static unsigned int get_index(unsigned int length, int index)
Definition: dmenu.c:258
static char * get_display_data(const Mode *data, unsigned int index, int *state, G_GNUC_UNUSED GList **list, int get_entry)
Definition: dmenu.c:269
static void dmenu_mode_free(Mode *sw)
Definition: dmenu.c:299
static gchar * dmenu_format_output_string(const DmenuModePrivateData *pd, const char *input)
Definition: dmenu.c:229
static void async_close_callback(GObject *source_object, GAsyncResult *res, G_GNUC_UNUSED gpointer user_data)
Definition: dmenu.c:106
static char * dmenu_get_message(const Mode *sw)
Definition: dmenu.c:496
static void dmenu_finish(RofiViewState *state, int retv)
Definition: dmenu.c:518
static void async_read_cancel(G_GNUC_UNUSED GCancellable *cancel, G_GNUC_UNUSED gpointer data)
Definition: dmenu.c:182
static void get_dmenu_sync(DmenuModePrivateData *pd)
Definition: dmenu.c:207
static void dmenu_print_results(DmenuModePrivateData *pd, const char *input)
Definition: dmenu.c:531
static void async_read_callback(GObject *source_object, GAsyncResult *res, gpointer user_data)
Definition: dmenu.c:139
static int get_dmenu_async(DmenuModePrivateData *pd, int sync_pre_read)
Definition: dmenu.c:187
static void dmenu_finalize(RofiViewState *state)
Definition: dmenu.c:551
static int dmenu_mode_init(Mode *sw)
Definition: dmenu.c:356
static unsigned int dmenu_mode_get_num_entries(const Mode *sw)
Definition: dmenu.c:223
void print_help_msg(const char *option, const char *type, const char *text, const char *def, int isatty)
Definition: xrmoptions.c:878
int dmenu_switcher_dialog(void)
Definition: dmenu.c:676
void print_dmenu_options(void)
Definition: dmenu.c:774
void parse_ranges(char *input, rofi_range_pair **list, unsigned int *length)
Definition: helper.c:1146
int find_arg_char(const char *const key, char *val)
Definition: helper.c:407
void helper_tokenize_free(rofi_int_matcher **tokens)
Definition: helper.c:119
void rofi_output_formatted_line(const char *format, const char *string, int selected_line, const char *filter)
Definition: helper.c:1163
char * rofi_expand_path(const char *input)
Definition: helper.c:713
int find_arg_str(const char *const key, char **val)
Definition: helper.c:310
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
Definition: helper.c:262
int find_arg_uint(const char *const key, unsigned int *val)
Definition: helper.c:349
int find_arg(const char *const key)
Definition: helper.c:301
int helper_token_match(rofi_int_matcher *const *tokens, const char *input)
Definition: helper.c:494
char * rofi_force_utf8(const gchar *data, ssize_t length)
Definition: helper.c:796
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)
Definition: mode.c:48
int mode_init(Mode *mode)
Definition: mode.c:42
MenuReturn
Definition: mode.h:65
void mode_set_private_data(Mode *mode, void *pd)
Definition: mode.c:136
void * mode_get_private_data(const Mode *mode)
Definition: mode.c:131
@ MENU_CUSTOM_COMMAND
Definition: mode.h:79
@ MENU_LOWER_MASK
Definition: mode.h:87
@ MENU_CANCEL
Definition: mode.h:69
@ MENU_CUSTOM_ACTION
Definition: mode.h:85
@ MENU_OK
Definition: mode.h:67
@ MENU_CUSTOM_INPUT
Definition: mode.h:73
void rofi_set_return_code(int code)
Definition: rofi.c:131
@ SELECTED
Definition: textbox.h:109
@ URGENT
Definition: textbox.h:105
@ ACTIVE
Definition: textbox.h:107
@ MARKUP
Definition: textbox.h:111
void rofi_view_set_overlay(RofiViewState *state, const char *text)
Definition: view.c:2148
void rofi_view_reload(void)
Definition: view.c:497
Mode * rofi_view_get_mode(RofiViewState *state)
Definition: view.c:2146
RofiViewState * rofi_view_get_active(void)
Definition: view.c:518
int rofi_view_error_dialog(const char *msg, int markup)
Definition: view.c:2018
void rofi_view_set_active(RofiViewState *state)
Definition: view.c:527
void rofi_view_restart(RofiViewState *state)
Definition: view.c:513
MenuFlags
Definition: view.h:48
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition: view.c:586
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition: view.c:550
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition: view.c:1932
void rofi_view_free(RofiViewState *state)
Definition: view.c:568
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition: view.c:607
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
Definition: view.c:590
unsigned int rofi_view_get_next_position(const RofiViewState *state)
Definition: view.c:594
@ MENU_PASSWORD
Definition: view.h:52
@ MENU_INDICATOR
Definition: view.h:58
@ MENU_NORMAL
Definition: view.h:50
void rofi_view_ellipsize_start(RofiViewState *state)
Definition: view.c:2169
@ P_INTEGER
Definition: rofi-types.h:12
void dmenuscript_parse_entry_extras(G_GNUC_UNUSED Mode *sw, DmenuScriptEntry *entry, char *buffer, G_GNUC_UNUSED size_t length)
Definition: script.c:79
Settings config
#define DEFAULT_MENU_LINES
Definition: settings.h:181
unsigned int num_urgent_list
Definition: dmenu.c:83
uint32_t * selected_list
Definition: dmenu.c:86
DmenuScriptEntry * cmd_list
Definition: dmenu.c:90
unsigned int cmd_list_real_length
Definition: dmenu.c:91
unsigned int num_selected_list
Definition: dmenu.c:87
unsigned int do_markup
Definition: dmenu.c:88
unsigned int selected_count
Definition: dmenu.c:94
GInputStream * input_stream
Definition: dmenu.c:102
GDataInputStream * data_input_stream
Definition: dmenu.c:103
gulong cancel_source
Definition: dmenu.c:101
gchar * column_separator
Definition: dmenu.c:97
GCancellable * cancel
Definition: dmenu.c:100
unsigned int num_active_list
Definition: dmenu.c:85
struct rofi_range_pair * urgent_list
Definition: dmenu.c:82
gboolean multi_select
Definition: dmenu.c:98
unsigned int cmd_list_length
Definition: dmenu.c:92
unsigned int only_selected
Definition: dmenu.c:93
gchar ** columns
Definition: dmenu.c:96
unsigned int selected_line
Definition: dmenu.c:79
struct rofi_range_pair * active_list
Definition: dmenu.c:84
char * message
Definition: dmenu.c:80
PropertyValue value
Definition: rofi-types.h:290
char * name
Definition: rofi-types.h:286
WindowLocation location
Definition: settings.h:84
unsigned int auto_select
Definition: settings.h:126
char * filter
Definition: settings.h:139
unsigned int case_sensitive
Definition: settings.h:114
char * display_name
Definition: mode-private.h:165
char * name
Definition: mode-private.h:163
void * private_data
Definition: mode-private.h:192
Property * rofi_theme_property_create(PropertyType type)
Definition: theme.c:81
void rofi_theme_widget_add_properties(ThemeWidget *widget, GHashTable *table)
Definition: theme.c:605
ThemeWidget * rofi_theme_find_or_create_name(ThemeWidget *base, const char *name)
Definition: theme.c:61
void rofi_theme_property_free(Property *p)
Definition: theme.c:182
ThemeWidget * rofi_theme
Definition: theme.h:90