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