rofi  1.7.5
rofi.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2012 Sean Pringle <sean.pringle@gmail.com>
6  * Copyright © 2013-2022 Qball Cow <qball@gmpclient.org>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  */
28 
30 #define G_LOG_DOMAIN "Rofi"
31 
32 #include "config.h"
33 #include <errno.h>
34 #include <gmodule.h>
35 #include <locale.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sysexits.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include <xcb/xcb.h>
44 
45 #include <glib-unix.h>
46 
47 #include <libgwater-xcb.h>
48 
49 #ifdef USE_NK_GIT_VERSION
50 #include "nkutils-git-version.h"
51 #ifdef NK_GIT_VERSION
52 #define GIT_VERSION NK_GIT_VERSION
53 #endif
54 #endif
55 
56 #include "resources.h"
57 
58 #include "display.h"
59 #include "rofi.h"
60 #include "settings.h"
61 
62 #include "helper.h"
63 #include "mode.h"
64 #include "modes/modes.h"
65 #include "widgets/textbox.h"
66 #include "xrmoptions.h"
67 
68 #include "view-internal.h"
69 #include "view.h"
70 
71 #include "rofi-icon-fetcher.h"
72 #include "theme.h"
73 
74 #include "timings.h"
75 
76 // Plugin abi version.
77 // TODO: move this check to mode.c
78 #include "mode-private.h"
79 
81 char *pidfile = NULL;
83 const char *cache_dir = NULL;
84 
86 GList *list_of_error_msgs = NULL;
87 GList *list_of_warning_msgs = NULL;
88 
89 static void rofi_collectmodes_destroy(void);
90 void rofi_add_error_message(GString *str) {
91  list_of_error_msgs = g_list_append(list_of_error_msgs, str);
92 }
94  if (list_of_error_msgs) {
95  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
96  iter = g_list_next(iter)) {
97  g_string_free((GString *)iter->data, TRUE);
98  }
99  g_list_free(list_of_error_msgs);
100  list_of_error_msgs = NULL;
101  }
102 }
103 void rofi_add_warning_message(GString *str) {
104  list_of_warning_msgs = g_list_append(list_of_warning_msgs, str);
105 }
107  if (list_of_warning_msgs) {
108  for (GList *iter = g_list_first(list_of_warning_msgs); iter != NULL;
109  iter = g_list_next(iter)) {
110  g_string_free((GString *)iter->data, TRUE);
111  }
112  g_list_free(list_of_warning_msgs);
113  list_of_warning_msgs = NULL;
114  }
115 }
116 
118 G_MODULE_EXPORT char *config_path = NULL;
121 Mode **modes = NULL;
122 
126 unsigned int num_available_modes = 0;
128 unsigned int num_modes = 0;
130 unsigned int curr_mode = 0;
131 
133 NkBindings *bindings = NULL;
134 
136 GMainLoop *main_loop = NULL;
137 
139 static int dmenu_mode = FALSE;
141 int return_code = EXIT_SUCCESS;
142 
143 void process_result(RofiViewState *state);
144 
145 void rofi_set_return_code(int code) { return_code = code; }
146 
147 unsigned int rofi_get_num_enabled_modes(void) { return num_modes; }
148 
149 const Mode *rofi_get_mode(unsigned int index) { return modes[index]; }
150 
158 static int mode_lookup(const char *name) {
159  for (unsigned int i = 0; i < num_modes; i++) {
160  if (strcmp(mode_get_name(modes[i]), name) == 0) {
161  return i;
162  }
163  }
164  return -1;
165 }
166 
170 static void teardown(int pfd) {
171  g_debug("Teardown");
172  // Cleanup font setup.
173  textbox_cleanup();
174 
176 
177  // Cleanup view
179 
180  // Cleanup pid file.
181  remove_pid_file(pfd);
182 }
183 static void run_mode_index(ModeMode mode) {
184  // Otherwise check if requested mode is enabled.
185  for (unsigned int i = 0; i < num_modes; i++) {
186  if (!mode_init(modes[i])) {
187  GString *str = g_string_new("Failed to initialize the mode: ");
188  g_string_append(str, modes[i]->name);
189  g_string_append(str, "\n");
190 
192  g_string_free(str, FALSE);
193  break;
194  }
195  }
196  // Error dialog must have been created.
197  if (rofi_view_get_active() != NULL) {
198  return;
199  }
200  curr_mode = mode;
201  RofiViewState *state =
203 
204  // User can pre-select a row.
205  if (find_arg("-selected-row") >= 0) {
206  unsigned int sr = 0;
207  find_arg_uint("-selected-row", &(sr));
208  rofi_view_set_selected_line(state, sr);
209  }
210  if (state) {
211  rofi_view_set_active(state);
212  }
213  if (rofi_view_get_active() == NULL) {
214  g_main_loop_quit(main_loop);
215  }
216 }
218  Mode *sw = state->sw;
219  // rofi_view_set_active ( NULL );
220  if (sw != NULL) {
221  unsigned int selected_line = rofi_view_get_selected_line(state);
222  ;
223  MenuReturn mretv = rofi_view_get_return_value(state);
224  char *input = g_strdup(rofi_view_get_user_input(state));
225  ModeMode retv = mode_result(sw, mretv, &input, selected_line);
226  {
227  if (state->text) {
228  if (input == NULL) {
229  textbox_text(state->text, "");
230  } else if (strcmp(rofi_view_get_user_input(state), input) != 0) {
231  textbox_text(state->text, input);
232  textbox_cursor_end(state->text);
233  }
234  }
235  }
236  g_free(input);
237 
238  ModeMode mode = curr_mode;
239  // Find next enabled
240  if (retv == NEXT_DIALOG) {
241  mode = (mode + 1) % num_modes;
242  } else if (retv == PREVIOUS_DIALOG) {
243  if (mode == 0) {
244  mode = num_modes - 1;
245  } else {
246  mode = (mode - 1) % num_modes;
247  }
248  } else if (retv == RELOAD_DIALOG) {
249  // do nothing.
250  } else if (retv == RESET_DIALOG) {
251  rofi_view_clear_input(state);
252  } else if (retv < MODE_EXIT) {
253  mode = (retv) % num_modes;
254  } else {
255  mode = retv;
256  }
257  if (mode != MODE_EXIT) {
261  rofi_view_switch_mode(state, modes[mode]);
262  curr_mode = mode;
263  return;
264  }
265  // On exit, free current view, and pop to one above.
267  rofi_view_free(state);
268  return;
269  }
270  // rofi_view_set_active ( NULL );
272  rofi_view_free(state);
273 }
274 
278 static void print_list_of_modes(int is_term) {
279  for (unsigned int i = 0; i < num_available_modes; i++) {
280  gboolean active = FALSE;
281  for (unsigned int j = 0; j < num_modes; j++) {
282  if (modes[j] == available_modes[i]) {
283  active = TRUE;
284  break;
285  }
286  }
287  printf(" • %s%s%s%s\n", active ? "+" : "",
288  is_term ? (active ? color_green : color_red) : "",
289  available_modes[i]->name, is_term ? color_reset : "");
290  }
291 }
292 static void print_main_application_options(int is_term) {
293  print_help_msg("-config", "[file]", "Load an alternative configuration.",
294  NULL, is_term);
295  print_help_msg("-no-config", "",
296  "Do not load configuration, use default values.", NULL,
297  is_term);
298  print_help_msg("-v,-version", "", "Print the version number and exit.", NULL,
299  is_term);
300  print_help_msg("-dmenu", "", "Start in dmenu mode.", NULL, is_term);
301  print_help_msg("-display", "[string]", "X server to contact.", "${DISPLAY}",
302  is_term);
303  print_help_msg("-h,-help", "", "This help message.", NULL, is_term);
304  print_help_msg("-e", "[string]",
305  "Show a dialog displaying the passed message and exit.", NULL,
306  is_term);
307  print_help_msg("-markup", "", "Enable pango markup where possible.", NULL,
308  is_term);
309  print_help_msg("-normal-window", "",
310  "Behave as a normal window. (experimental)", NULL, is_term);
311  print_help_msg("-show", "[mode]",
312  "Show the mode 'mode' and exit. The mode has to be enabled.",
313  NULL, is_term);
314  print_help_msg("-no-lazy-grab", "",
315  "Disable lazy grab that, when fail to grab keyboard, does not "
316  "block but retry later.",
317  NULL, is_term);
318  print_help_msg("-no-plugins", "", "Disable loading of external plugins.",
319  NULL, is_term);
320  print_help_msg("-plugin-path", "",
321  "Directory used to search for rofi plugins. *DEPRECATED*",
322  NULL, is_term);
323  print_help_msg("-dump-config", "",
324  "Dump the current configuration in rasi format and exit.",
325  NULL, is_term);
326  print_help_msg("-dump-theme", "",
327  "Dump the current theme in rasi format and exit.", NULL,
328  is_term);
329 }
330 static void help(G_GNUC_UNUSED int argc, char **argv) {
331  int is_term = isatty(fileno(stdout));
332  printf("%s usage:\n", argv[0]);
333  printf("\t%s [-options ...]\n\n", argv[0]);
334  printf("Command line only options:\n");
336  printf("DMENU command line options:\n");
338  printf("Global options:\n");
339  print_options();
340  printf("\n");
342  printf("\n");
343  printf("Detected modes:\n");
344  print_list_of_modes(is_term);
345  printf("\n");
346  printf("Detected user scripts:\n");
347  script_user_list(is_term);
348  printf("\n");
349  printf("Compile time options:\n");
350  printf("\t• Pango version %s\n", pango_version_string());
351 #ifdef WINDOW_MODE
352  printf("\t• window %senabled%s\n", is_term ? color_green : "",
353  is_term ? color_reset : "");
354 #else
355  printf("\t• window %sdisabled%s\n", is_term ? color_red : "",
356  is_term ? color_reset : "");
357 #endif
358 #ifdef ENABLE_DRUN
359  printf("\t• drun %senabled%s\n", is_term ? color_green : "",
360  is_term ? color_reset : "");
361 #else
362  printf("\t• drun %sdisabled%s\n", is_term ? color_red : "",
363  is_term ? color_reset : "");
364 #endif
365 #ifdef ENABLE_GCOV
366  printf("\t• gcov %senabled%s\n", is_term ? color_green : "",
367  is_term ? color_reset : "");
368 #else
369  printf("\t• gcov %sdisabled%s\n", is_term ? color_red : "",
370  is_term ? color_reset : "");
371 #endif
372 #ifdef ENABLE_ASAN
373  printf("\t• asan %senabled%s\n", is_term ? color_green : "",
374  is_term ? color_reset : "");
375 #else
376  printf("\t• asan %sdisabled%s\n", is_term ? color_red : "",
377  is_term ? color_reset : "");
378 #endif
379  printf("\n");
380  printf("For more information see: %sman rofi%s\n", is_term ? color_bold : "",
381  is_term ? color_reset : "");
382 #ifdef GIT_VERSION
383  printf(" Version: %s" GIT_VERSION "%s\n",
384  is_term ? color_bold : "", is_term ? color_reset : "");
385 #else
386  printf(" Version: %s" VERSION "%s\n",
387  is_term ? color_bold : "", is_term ? color_reset : "");
388 #endif
389  printf(" Bugreports: %s" PACKAGE_BUGREPORT "%s\n",
390  is_term ? color_bold : "", is_term ? color_reset : "");
391  printf(" Support: %s" PACKAGE_URL "%s\n",
392  is_term ? color_bold : "", is_term ? color_reset : "");
393  printf(" %s#rofi @ libera.chat%s\n",
394  is_term ? color_bold : "", is_term ? color_reset : "");
395  if (find_arg("-no-config") < 0) {
396  if (config_path) {
397  printf(" Configuration file: %s%s%s\n", is_term ? color_bold : "",
398  config_path, is_term ? color_reset : "");
399  }
400  } else {
401  printf(" Configuration file: %sDisabled%s\n",
402  is_term ? color_bold : "", is_term ? color_reset : "");
403  }
405 }
406 
407 static void help_print_disabled_mode(const char *mode) {
408  int is_term = isatty(fileno(stdout));
409  // Only output to terminal
410  if (is_term) {
411  fprintf(stderr, "Mode %s%s%s is not enabled. I have enabled it for now.\n",
412  color_red, mode, color_reset);
413  fprintf(stderr,
414  "Please consider adding %s%s%s to the list of enabled modes: "
415  "%smodes: [%s%s%s,%s]%s.\n",
418  }
419 }
420 static void help_print_mode_not_found(const char *mode) {
421  GString *str = g_string_new("");
422  g_string_printf(
423  str, "Mode %s is not found.\nThe following modes are known:\n", mode);
424  for (unsigned int i = 0; i < num_available_modes; i++) {
425  gboolean active = FALSE;
426  for (unsigned int j = 0; j < num_modes; j++) {
427  if (modes[j] == available_modes[i]) {
428  active = TRUE;
429  break;
430  }
431  }
432  g_string_append_printf(str, " * %s%s\n", active ? "+" : "",
433  available_modes[i]->name);
434  }
436 }
437 static void help_print_no_arguments(void) {
438 
439  GString *emesg = g_string_new(
440  "<span size=\"x-large\">Rofi is unsure what to show.</span>\n\n");
441  g_string_append(emesg, "Please specify the mode you want to show.\n\n");
442  g_string_append(
443  emesg, " <b>rofi</b> -show <span color=\"green\">{mode}</span>\n\n");
444  g_string_append(emesg, "The following modes are enabled:\n");
445  for (unsigned int j = 0; j < num_modes; j++) {
446  g_string_append_printf(emesg, " • <span color=\"green\">%s</span>\n",
447  modes[j]->name);
448  }
449  g_string_append(emesg, "\nThe following modes can be enabled:\n");
450  for (unsigned int i = 0; i < num_available_modes; i++) {
451  gboolean active = FALSE;
452  for (unsigned int j = 0; j < num_modes; j++) {
453  if (modes[j] == available_modes[i]) {
454  active = TRUE;
455  break;
456  }
457  }
458  if (!active) {
459  g_string_append_printf(emesg, " • <span color=\"red\">%s</span>\n",
460  available_modes[i]->name);
461  }
462  }
463  g_string_append(emesg, "\nTo activate a mode, add it to the list in "
464  "the <span color=\"green\">modes</span> "
465  "setting.\n");
467  rofi_set_return_code(EXIT_SUCCESS);
468 }
469 
473 static void cleanup(void) {
474  for (unsigned int i = 0; i < num_modes; i++) {
475  mode_destroy(modes[i]);
476  }
478  if (main_loop != NULL) {
479  g_main_loop_unref(main_loop);
480  main_loop = NULL;
481  }
482  // Cleanup
483  display_cleanup();
484 
485  nk_bindings_free(bindings);
486 
487  // Cleaning up memory allocated by the Xresources file.
489  g_free(modes);
490 
491  g_free(config_path);
492 
495 
496  if (rofi_theme) {
498  rofi_theme = NULL;
499  }
500  TIMINGS_STOP();
504 
506  if (rofi_configuration) {
508  rofi_configuration = NULL;
509  }
510 }
511 
516 Mode *rofi_collect_modes_search(const char *name) {
517  for (unsigned int i = 0; i < num_available_modes; i++) {
518  if (g_strcmp0(name, available_modes[i]->name) == 0) {
519  return available_modes[i];
520  }
521  }
522  return NULL;
523 }
529 static gboolean rofi_collectmodes_add(Mode *mode) {
530  Mode *m = rofi_collect_modes_search(mode->name);
531  if (m == NULL) {
533  g_realloc(available_modes, sizeof(Mode *) * (num_available_modes + 1));
534  // Set mode.
537  return TRUE;
538  }
539  return FALSE;
540 }
541 
542 static void rofi_collectmodes_dir(const char *base_dir) {
543  g_debug("Looking into: %s for plugins", base_dir);
544  GDir *dir = g_dir_open(base_dir, 0, NULL);
545  if (dir) {
546  const char *dn = NULL;
547  while ((dn = g_dir_read_name(dir))) {
548  if (!g_str_has_suffix(dn, G_MODULE_SUFFIX)) {
549  continue;
550  }
551  char *fn = g_build_filename(base_dir, dn, NULL);
552  g_debug("Trying to open: %s plugin", fn);
553  GModule *mod =
554  g_module_open(fn, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
555  if (mod) {
556  Mode *m = NULL;
557  if (g_module_symbol(mod, "mode", (gpointer *)&m)) {
558  if (m->abi_version != ABI_VERSION) {
559  g_warning("ABI version of plugin: '%s' does not match: %08X "
560  "expecting: %08X",
561  dn, m->abi_version, ABI_VERSION);
562  g_module_close(mod);
563  } else {
564  m->module = mod;
565  if (!rofi_collectmodes_add(m)) {
566  g_module_close(mod);
567  }
568  }
569  } else {
570  g_warning("Symbol 'mode' not found in module: %s", dn);
571  g_module_close(mod);
572  }
573  } else {
574  g_warning("Failed to open 'mode' plugin: '%s', error: %s", dn,
575  g_module_error());
576  }
577  g_free(fn);
578  }
579  g_dir_close(dir);
580  }
581 }
582 
586 static void rofi_collect_modes(void) {
587 #ifdef WINDOW_MODE
588  rofi_collectmodes_add(&window_mode);
589  rofi_collectmodes_add(&window_mode_cd);
590 #endif
593 #ifdef ENABLE_DRUN
594  rofi_collectmodes_add(&drun_mode);
595 #endif
599 
600  if (find_arg("-no-plugins") < 0) {
601  find_arg_str("-plugin-path", &(config.plugin_path));
602  g_debug("Parse plugin path: %s", config.plugin_path);
604  /* ROFI_PLUGIN_PATH */
605  const char *path = g_getenv("ROFI_PLUGIN_PATH");
606  if (path != NULL) {
607  gchar **paths = g_strsplit(path, ":", -1);
608  for (unsigned int i = 0; paths[i]; i++) {
609  rofi_collectmodes_dir(paths[i]);
610  }
611  g_strfreev(paths);
612  }
613  }
615 }
616 
620 static void rofi_collectmodes_setup(void) {
621  for (unsigned int i = 0; i < num_available_modes; i++) {
623  }
624 }
625 static void rofi_collectmodes_destroy(void) {
626  for (unsigned int i = 0; i < num_available_modes; i++) {
627  if (available_modes[i]->module) {
628  GModule *mod = available_modes[i]->module;
629  available_modes[i] = NULL;
630  g_module_close(mod);
631  }
632  if (available_modes[i]) {
633  mode_free(&(available_modes[i]));
634  }
635  }
636  g_free(available_modes);
637  available_modes = NULL;
639 }
640 
648 static int add_mode(const char *token) {
649  unsigned int index = num_modes;
650  // Resize and add entry.
651  modes = (Mode **)g_realloc(modes, sizeof(Mode *) * (num_modes + 1));
652 
653  Mode *mode = rofi_collect_modes_search(token);
654  if (mode) {
655  modes[num_modes] = mode;
656  num_modes++;
657  } else if (script_mode_is_valid(token)) {
658  // If not build in, use custom mode.
659  Mode *sw = script_mode_parse_setup(token);
660  if (sw != NULL) {
661  // Add to available list, so combi can find it.
663  mode_set_config(sw);
664  modes[num_modes] = sw;
665  num_modes++;
666  }
667  }
668  return (index == num_modes) ? -1 : (int)index;
669 }
670 static gboolean setup_modes(void) {
671  const char *const sep = ",#";
672  char *savept = NULL;
673  // Make a copy, as strtok will modify it.
674  char *mode_str = g_strdup(config.modes);
675  // Split token on ','. This modifies mode_str.
676  for (char *token = strtok_r(mode_str, sep, &savept); token != NULL;
677  token = strtok_r(NULL, sep, &savept)) {
678  if (add_mode(token) == -1) {
680  }
681  }
682  // Free string that was modified by strtok_r
683  g_free(mode_str);
684  return FALSE;
685 }
686 
691 void rofi_quit_main_loop(void) { g_main_loop_quit(main_loop); }
692 
693 static gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data) {
694  // Break out of loop.
695  g_main_loop_quit(main_loop);
696  return G_SOURCE_CONTINUE;
697 }
698 static void show_error_dialog(void) {
699  GString *emesg =
700  g_string_new("The following errors were detected when starting rofi:\n");
701  GList *iter = g_list_first(list_of_error_msgs);
702  int index = 0;
703  for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
704  GString *msg = (GString *)(iter->data);
705  g_string_append(emesg, "\n\n");
706  g_string_append(emesg, msg->str);
707  index++;
708  }
709  if (g_list_length(iter) > 1) {
710  g_string_append_printf(emesg, "\nThere are <b>%u</b> more errors.",
711  g_list_length(iter) - 1);
712  }
714  g_string_free(emesg, TRUE);
715  rofi_set_return_code(EX_DATAERR);
716 }
717 
718 static gboolean startup(G_GNUC_UNUSED gpointer data) {
719  TICK_N("Startup");
720  // flags to run immediately and exit
721  char *sname = NULL;
722  char *msg = NULL;
723  MenuFlags window_flags = MENU_NORMAL;
724 
725  if (find_arg("-normal-window") >= 0) {
726  window_flags |= MENU_NORMAL_WINDOW;
727  }
728  TICK_N("Grab keyboard");
729  __create_window(window_flags);
730  TICK_N("Create Window");
731  // Parse the keybindings.
732  TICK_N("Parse ABE");
733  // Sanity check
735  TICK_N("Config sanity check");
736 
737  if (list_of_error_msgs != NULL) {
739  return G_SOURCE_REMOVE;
740  }
741  if (list_of_warning_msgs != NULL) {
742  for (GList *iter = g_list_first(list_of_warning_msgs); iter != NULL;
743  iter = g_list_next(iter)) {
744  fputs(((GString *)iter->data)->str, stderr);
745  fputs("\n", stderr);
746  }
747  }
748  // Dmenu mode.
749  if (dmenu_mode == TRUE) {
750  // force off sidebar mode:
751  config.sidebar_mode = FALSE;
752  int retv = dmenu_mode_dialog();
753  if (retv) {
754  rofi_set_return_code(EXIT_SUCCESS);
755  // Directly exit.
756  g_main_loop_quit(main_loop);
757  }
758  } else if (find_arg_str("-e", &(msg))) {
759  int markup = FALSE;
760  if (find_arg("-markup") >= 0) {
761  markup = TRUE;
762  }
763  if (!rofi_view_error_dialog(msg, markup)) {
764  g_main_loop_quit(main_loop);
765  }
766  } else if (find_arg_str("-show", &sname) == TRUE) {
767  int index = mode_lookup(sname);
768  if (index < 0) {
769  // Add it to the list
770  index = add_mode(sname);
771  // Complain
772  if (index >= 0) {
774  }
775  // Run it anyway if found.
776  }
777  if (index >= 0) {
778  run_mode_index(index);
779  } else {
782  return G_SOURCE_REMOVE;
783  }
784  } else if (find_arg("-show") >= 0 && num_modes > 0) {
785  run_mode_index(0);
786  } else {
788 
789  // g_main_loop_quit(main_loop);
790  }
791 
792  return G_SOURCE_REMOVE;
793 }
794 
795 static gboolean record(G_GNUC_UNUSED void *data) {
797  return G_SOURCE_CONTINUE;
798 }
799 static void rofi_custom_log_function(const char *log_domain,
800  G_GNUC_UNUSED GLogLevelFlags log_level,
801  const gchar *message, gpointer user_data) {
802  int fp = GPOINTER_TO_INT(user_data);
803  dprintf(fp, "[%s]: %s\n", log_domain == NULL ? "default" : log_domain,
804  message);
805 }
814 int main(int argc, char *argv[]) {
815  cmd_set_arguments(argc, argv);
816  if (find_arg("-log") >= 0) {
817  char *logfile = NULL;
818  find_arg_str("-log", &logfile);
819  if (logfile != NULL) {
820  int fp = open(logfile, O_CLOEXEC | O_APPEND | O_CREAT | O_WRONLY,
821  S_IRUSR | S_IWUSR);
822  if (fp != -1) {
823  g_log_set_default_handler(rofi_custom_log_function,
824  GINT_TO_POINTER(fp));
825 
826  } else {
827  g_error("Failed to open logfile '%s': %s.", logfile, strerror(errno));
828  }
829 
830  } else {
831  g_warning("Option '-log' should pass in a filename.");
832  }
833  }
834  TIMINGS_START();
835 
836  // Version
837  if (find_arg("-v") >= 0 || find_arg("-version") >= 0) {
838 #ifdef GIT_VERSION
839  g_print("Version: " GIT_VERSION "\n");
840 #else
841  g_print("Version: " VERSION "\n");
842 #endif
843  return EXIT_SUCCESS;
844  }
845 
846  if (find_arg("-rasi-validate") >= 0) {
847  char *str = NULL;
848  find_arg_str("-rasi-validate", &str);
849  if (str != NULL) {
850  int retv = rofi_theme_rasi_validate(str);
851  cleanup();
852  return retv;
853  }
854  fprintf(stderr, "Usage: %s -rasi-validate my-theme.rasi", argv[0]);
855  return EXIT_FAILURE;
856  }
857 
858  {
859  const char *ro_pid = g_getenv("ROFI_OUTSIDE");
860  if (ro_pid != NULL) {
861  pid_t ro_pidi = (pid_t)g_ascii_strtoll(ro_pid, NULL, 0);
862  if (kill(ro_pidi, 0) == 0) {
863  printf("Do not launch rofi from inside rofi.\r\n");
864  return EXIT_FAILURE;
865  }
866  }
867  }
868 
869  // Detect if we are in dmenu mode.
870  // This has two possible causes.
871  // 1 the user specifies it on the command-line.
872  if (find_arg("-dmenu") >= 0) {
873  dmenu_mode = TRUE;
874  }
875  // 2 the binary that executed is called dmenu (e.g. symlink to rofi)
876  else {
877  // Get the base name of the executable called.
878  char *base_name = g_path_get_basename(argv[0]);
879  const char *const dmenu_str = "dmenu";
880  dmenu_mode = (strcmp(base_name, dmenu_str) == 0);
881  // Free the basename for dmenu detection.
882  g_free(base_name);
883  }
884  TICK();
885 
886  // Create pid file path.
887  const char *path = g_get_user_runtime_dir();
888  if (path) {
889  if (g_mkdir_with_parents(path, 0700) < 0) {
890  g_warning("Failed to create user runtime directory: %s with error: %s",
891  path, g_strerror(errno));
892  pidfile = g_build_filename(g_get_home_dir(), ".rofi.pid", NULL);
893  } else {
894  pidfile = g_build_filename(path, "rofi.pid", NULL);
895  }
896  }
897  config_parser_add_option(xrm_String, "pid", (void **)&pidfile,
898  "Pidfile location");
899 
901  if (find_arg("-no-default-config") < 0) {
902  GBytes *theme_data = g_resource_lookup_data(
903  resources_get_resource(), "/org/qtools/rofi/default_configuration.rasi",
904  G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
905  if (theme_data) {
906  const char *theme = g_bytes_get_data(theme_data, NULL);
907  if (rofi_theme_parse_string((const char *)theme)) {
908  g_warning("Failed to parse default configuration. Giving up..");
909  if (list_of_error_msgs) {
910  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
911  iter = g_list_next(iter)) {
912  g_warning("Error: %s%s%s", color_bold, ((GString *)iter->data)->str,
913  color_reset);
914  }
915  }
916  rofi_configuration = NULL;
917  cleanup();
918  return EXIT_FAILURE;
919  }
920  g_bytes_unref(theme_data);
921  }
922  }
923 
924  if (find_arg("-config") < 0) {
925  const char *cpath = g_get_user_config_dir();
926  if (cpath) {
927  config_path = g_build_filename(cpath, "rofi", "config.rasi", NULL);
928  }
929  } else {
930  char *c = NULL;
931  find_arg_str("-config", &c);
933  }
934 
935  TICK();
936  if (setlocale(LC_ALL, "") == NULL) {
937  g_warning("Failed to set locale.");
938  cleanup();
939  return EXIT_FAILURE;
940  }
941 
942  TICK_N("Setup Locale");
944  TICK_N("Collect MODES");
946  TICK_N("Setup MODES");
947 
948  main_loop = g_main_loop_new(NULL, FALSE);
949 
950  TICK_N("Setup mainloop");
951 
952  bindings = nk_bindings_new(0lu);
953  TICK_N("NK Bindings");
954 
956  g_warning("Connection has error");
957  cleanup();
958  return EXIT_FAILURE;
959  }
960  TICK_N("Setup Display");
961 
962  // Setup keybinding
963  setup_abe();
964  TICK_N("Setup abe");
965 
966  if (find_arg("-no-config") < 0) {
967  // Load distro default settings
968  gboolean found_system = FALSE;
969  const char *const *dirs = g_get_system_config_dirs();
970  if (dirs) {
971  for (unsigned int i = 0; !found_system && dirs[i]; i++) {
973  gchar *etc = g_build_filename(dirs[i], "rofi.rasi", NULL);
974  g_debug("Look for default config file: %s", etc);
975  if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
976  g_debug("Parsing: %s", etc);
978  found_system = TRUE;
979  }
980  g_free(etc);
981  }
982  }
983  if (!found_system) {
985  gchar *etc = g_build_filename(SYSCONFDIR, "rofi.rasi", NULL);
986  g_debug("Look for default config file: %s", etc);
987  if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
988  g_debug("Look for default config file: %s", etc);
990  }
991  g_free(etc);
992  }
993 
994  if (config_path && g_file_test(config_path, G_FILE_TEST_IS_REGULAR)) {
997  rofi_theme = NULL;
998  }
999  }
1000  }
1001  find_arg_str("-theme", &(config.theme));
1002  if (config.theme) {
1003  TICK_N("Parse theme");
1004  rofi_theme_reset();
1006  g_warning("Failed to parse theme: \"%s\"", config.theme);
1007  // TODO: instantiate fallback theme.?
1009  rofi_theme = NULL;
1010  }
1011  TICK_N("Parsed theme");
1012  }
1013  // Parse command line for settings, independent of other -no-config.
1014  if (list_of_error_msgs == NULL) {
1015  // Only call this when there are no errors.
1016  // This might clear existing errors.
1018  }
1019  TICK_N("Load cmd config ");
1020 
1021  // Get the path to the cache dir.
1022  cache_dir = g_get_user_cache_dir();
1023 
1024  if (config.cache_dir != NULL) {
1026  }
1027 
1028  if (g_mkdir_with_parents(cache_dir, 0700) < 0) {
1029  g_warning("Failed to create cache directory: %s", g_strerror(errno));
1030  return EXIT_FAILURE;
1031  }
1032 
1034  char *windowid = NULL;
1035  if (!dmenu_mode) {
1036  // setup_modes
1037  if (setup_modes()) {
1038  cleanup();
1039  return EXIT_FAILURE;
1040  }
1041  TICK_N("Setup Modes");
1042  } else {
1043  // Hack for dmenu compatibility.
1044  if (find_arg_str("-w", &windowid) == TRUE) {
1045  config.monitor = g_strdup_printf("wid:%s", windowid);
1046  windowid = config.monitor;
1047  }
1048  }
1049 
1053  const char **theme_str = find_arg_strv("-theme-str");
1054  if (theme_str) {
1055  for (int index = 0; theme_str && theme_str[index]; index++) {
1056  if (rofi_theme_parse_string(theme_str[index])) {
1057  g_warning("Failed to parse -theme-str option: \"%s\"",
1058  theme_str[index]);
1060  rofi_theme = NULL;
1061  }
1062  }
1063  g_free(theme_str);
1064  }
1065 
1067  if (find_arg("-dump-theme") >= 0) {
1069  cleanup();
1070  return EXIT_SUCCESS;
1071  }
1072  if (find_arg("-dump-processed-theme") >= 0) {
1075  cleanup();
1076  return EXIT_SUCCESS;
1077  }
1078  if (find_arg("-dump-config") >= 0) {
1079  config_parse_dump_config_rasi_format(stdout, FALSE);
1080  cleanup();
1081  return EXIT_SUCCESS;
1082  }
1083  // Dump.
1084  // catch help request
1085  if (find_arg("-h") >= 0 || find_arg("-help") >= 0 ||
1086  find_arg("--help") >= 0) {
1087  help(argc, argv);
1088  cleanup();
1089  return EXIT_SUCCESS;
1090  }
1091 
1092  unsigned int interval = 1;
1093  if (find_arg_uint("-record-screenshots", &interval)) {
1094  g_timeout_add((guint)(1000 / (double)interval), record, NULL);
1095  }
1096  if (find_arg("-benchmark-ui") >= 0) {
1097  config.benchmark_ui = TRUE;
1098  }
1099 
1101  TICK_N("Workers initialize");
1103  TICK_N("Icon fetcher initialize");
1104 
1105  gboolean kill_running = FALSE;
1106  if (find_arg("-replace") >= 0) {
1107  kill_running = TRUE;
1108  }
1109  // Create pid file
1110  int pfd = create_pid_file(pidfile, kill_running);
1111  TICK_N("Pid file created");
1112  if (pfd < 0) {
1113  cleanup();
1114  return EXIT_FAILURE;
1115  }
1116  textbox_setup();
1117  TICK_N("Text box setup");
1118 
1119  if (!display_late_setup()) {
1120  g_warning("Failed to properly finish display setup");
1121  cleanup();
1122  return EXIT_FAILURE;
1123  }
1124  TICK_N("Setup late Display");
1125 
1128  TICK_N("Theme setup");
1129 
1130  // Setup signal handling sources.
1131  // SIGINT
1132  g_unix_signal_add(SIGINT, main_loop_signal_handler_int, NULL);
1133 
1134  g_idle_add(startup, NULL);
1135 
1136  // Start mainloop.
1137  g_main_loop_run(main_loop);
1138  teardown(pfd);
1139  cleanup();
1140 
1141  /* dirty hack */
1142  g_free(windowid);
1143  return return_code;
1144 }
1145 
1147 extern GList *list_of_error_msgs;
1148 int rofi_theme_rasi_validate(const char *filename) {
1149  rofi_theme_parse_file(filename);
1151  if (list_of_error_msgs == NULL && list_of_warning_msgs == NULL) {
1152  return EXIT_SUCCESS;
1153  }
1154 
1155  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
1156  iter = g_list_next(iter)) {
1157  fputs(((GString *)iter->data)->str, stderr);
1158  fputs("\n", stderr);
1159  }
1160  for (GList *iter = g_list_first(list_of_warning_msgs); iter != NULL;
1161  iter = g_list_next(iter)) {
1162  fputs(((GString *)iter->data)->str, stderr);
1163  fputs("\n", stderr);
1164  }
1165 
1166  return EXIT_FAILURE;
1167 }
Mode combi_mode
Definition: combi.c:324
void config_parse_cmd_options(void)
Definition: xrmoptions.c:560
void print_options(void)
Definition: xrmoptions.c:958
void config_parser_add_option(XrmOptionType type, const char *key, void **value, const char *comment)
Definition: xrmoptions.c:455
void print_help_msg(const char *option, const char *type, const char *text, const char *def, int isatty)
Definition: xrmoptions.c:975
void config_parse_dump_config_rasi_format(FILE *out, gboolean changes)
Dump configuration in rasi format.
Definition: xrmoptions.c:820
@ xrm_String
Definition: xrmoptions.h:74
void config_xresource_free(void)
Definition: xrmoptions.c:758
int dmenu_mode_dialog(void)
Definition: dmenu.c:889
void print_dmenu_options(void)
Definition: dmenu.c:970
Mode file_browser_mode
Definition: filebrowser.c:676
void cmd_set_arguments(int argc, char **argv)
Definition: helper.c:70
const char ** find_arg_strv(const char *const key)
Definition: helper.c:321
void remove_pid_file(int fd)
Definition: helper.c:620
char * rofi_expand_path(const char *input)
Definition: helper.c:740
int find_arg_str(const char *const key, char **val)
Definition: helper.c:311
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 create_pid_file(const char *pidfile, gboolean kill_running)
Definition: helper.c:562
int config_sanity_check(void)
Definition: helper.c:647
Mode help_keys_mode
Definition: help-keys.c:111
void rofi_icon_fetcher_destroy(void)
void rofi_icon_fetcher_init(void)
gboolean parse_keys_abe(NkBindings *bindings)
Definition: keyb.c:406
void setup_abe(void)
Definition: keyb.c:372
void mode_destroy(Mode *mode)
Definition: mode.c:52
int mode_init(Mode *mode)
Definition: mode.c:43
void mode_free(Mode **mode)
Definition: mode.c:150
ModeMode mode_result(Mode *mode, int menu_retv, char **input, unsigned int selected_line)
Definition: mode.c:119
MenuReturn
Definition: mode.h:65
ModeMode
Definition: mode.h:49
const char * mode_get_name(const Mode *mode)
Definition: mode.c:145
void mode_set_config(Mode *mode)
Definition: mode.c:188
@ MODE_EXIT
Definition: mode.h:51
@ NEXT_DIALOG
Definition: mode.h:53
@ RELOAD_DIALOG
Definition: mode.h:55
@ PREVIOUS_DIALOG
Definition: mode.h:57
@ RESET_DIALOG
Definition: mode.h:59
void rofi_quit_main_loop(void)
Definition: rofi.c:691
#define color_reset
Definition: rofi.h:107
#define color_bold
Definition: rofi.h:109
unsigned int rofi_get_num_enabled_modes(void)
Definition: rofi.c:147
void rofi_clear_error_messages(void)
Definition: rofi.c:93
void rofi_clear_warning_messages(void)
Definition: rofi.c:106
#define color_red
Definition: rofi.h:115
#define ERROR_MSG_MARKUP
Definition: rofi.h:128
void rofi_set_return_code(int code)
Definition: rofi.c:145
const Mode * rofi_get_mode(unsigned int index)
Definition: rofi.c:149
Mode * rofi_collect_modes_search(const char *name)
Definition: rofi.c:516
const char * cache_dir
Definition: rofi.c:83
void rofi_add_error_message(GString *str)
Definition: rofi.c:90
#define color_green
Definition: rofi.h:113
void rofi_add_warning_message(GString *str)
Definition: rofi.c:103
Mode run_mode
Definition: run.c:562
void script_mode_gather_user_scripts(void)
Definition: script.c:481
Mode * script_mode_parse_setup(const char *str)
Definition: script.c:519
gboolean script_mode_is_valid(const char *token)
Definition: script.c:574
void script_user_list(gboolean is_term)
Definition: script.c:581
void script_mode_cleanup(void)
Definition: script.c:474
Mode ssh_mode
Definition: ssh.c:637
#define TICK()
Definition: timings.h:64
#define TIMINGS_START()
Definition: timings.h:60
#define TIMINGS_STOP()
Definition: timings.h:73
#define TICK_N(a)
Definition: timings.h:69
void textbox_cleanup(void)
Definition: textbox.c:890
void textbox_setup(void)
Definition: textbox.c:864
void textbox_cursor_end(textbox *tb)
Definition: textbox.c:645
void textbox_text(textbox *tb, const char *text)
Definition: textbox.c:358
void rofi_view_cleanup()
Definition: view.c:2241
void __create_window(MenuFlags menu_flags)
Definition: view.c:782
void rofi_view_clear_input(RofiViewState *state)
Definition: view.c:2336
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Definition: view.c:2347
void rofi_view_remove_active(RofiViewState *state)
Definition: view.c:551
RofiViewState * rofi_view_get_active(void)
Definition: view.c:549
int rofi_view_error_dialog(const char *msg, int markup)
Definition: view.c:2191
void rofi_view_set_active(RofiViewState *state)
Definition: view.c:558
MenuFlags
Definition: view.h:48
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition: view.c:617
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition: view.c:581
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition: view.c:2103
void rofi_view_free(RofiViewState *state)
Definition: view.c:599
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition: view.c:638
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
Definition: view.c:621
@ MENU_NORMAL_WINDOW
Definition: view.h:54
@ MENU_NORMAL
Definition: view.h:50
void rofi_capture_screenshot(void)
Definition: view.c:179
void rofi_view_workers_initialize(void)
Definition: view.c:2287
void rofi_view_workers_finalize(void)
Definition: view.c:2314
#define ABI_VERSION
Definition: mode-private.h:35
static void help(G_GNUC_UNUSED int argc, char **argv)
Definition: rofi.c:330
static void rofi_collect_modes(void)
Definition: rofi.c:586
int main(int argc, char *argv[])
Definition: rofi.c:814
GList * list_of_warning_msgs
Definition: rofi.c:87
GList * list_of_error_msgs
Definition: rofi.c:86
static gboolean record(G_GNUC_UNUSED void *data)
Definition: rofi.c:795
G_MODULE_EXPORT char * config_path
Definition: rofi.c:118
NkBindings * bindings
Definition: rofi.c:133
static void print_main_application_options(int is_term)
Definition: rofi.c:292
static void print_list_of_modes(int is_term)
Definition: rofi.c:278
static void run_mode_index(ModeMode mode)
Definition: rofi.c:183
static void rofi_custom_log_function(const char *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, const gchar *message, gpointer user_data)
Definition: rofi.c:799
static void help_print_mode_not_found(const char *mode)
Definition: rofi.c:420
static void cleanup(void)
Definition: rofi.c:473
Mode ** modes
Definition: rofi.c:121
static gboolean startup(G_GNUC_UNUSED gpointer data)
Definition: rofi.c:718
static gboolean setup_modes(void)
Definition: rofi.c:670
Mode ** available_modes
Definition: rofi.c:124
int rofi_theme_rasi_validate(const char *filename)
Definition: rofi.c:1148
unsigned int num_modes
Definition: rofi.c:128
static void rofi_collectmodes_setup(void)
Definition: rofi.c:620
GMainLoop * main_loop
Definition: rofi.c:136
static void teardown(int pfd)
Definition: rofi.c:170
static gboolean rofi_collectmodes_add(Mode *mode)
Definition: rofi.c:529
static void rofi_collectmodes_destroy(void)
Definition: rofi.c:625
char * pidfile
Definition: rofi.c:81
int return_code
Definition: rofi.c:141
void process_result(RofiViewState *state)
Definition: rofi.c:217
static int add_mode(const char *token)
Definition: rofi.c:648
static gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data)
Definition: rofi.c:693
static void show_error_dialog(void)
Definition: rofi.c:698
static void help_print_no_arguments(void)
Definition: rofi.c:437
static int dmenu_mode
Definition: rofi.c:139
static int mode_lookup(const char *name)
Definition: rofi.c:158
static void help_print_disabled_mode(const char *mode)
Definition: rofi.c:407
unsigned int num_available_modes
Definition: rofi.c:126
static void rofi_collectmodes_dir(const char *base_dir)
Definition: rofi.c:542
unsigned int curr_mode
Definition: rofi.c:130
Settings config
textbox * text
Definition: view-internal.h:59
char * cache_dir
Definition: settings.h:163
char * modes
Definition: settings.h:57
char * theme
Definition: settings.h:150
char * plugin_path
Definition: settings.h:152
char * filter
Definition: settings.h:139
unsigned int sidebar_mode
Definition: settings.h:120
gboolean benchmark_ui
Definition: settings.h:173
char * monitor
Definition: settings.h:137
unsigned int abi_version
Definition: mode-private.h:161
GModule * module
Definition: mode-private.h:204
char * name
Definition: mode-private.h:163
void rofi_theme_free_parsed_files(void)
Definition: theme.c:51
void rofi_theme_print_parsed_files(gboolean is_term)
Definition: theme.c:56
void rofi_theme_parse_process_links(void)
Definition: theme.c:1615
void rofi_theme_parse_process_conditionals(void)
Definition: theme.c:1619
void rofi_theme_print(ThemeWidget *widget)
Definition: theme.c:585
void rofi_theme_reset(void)
Definition: theme.c:226
void rofi_theme_free(ThemeWidget *widget)
Definition: theme.c:232
gboolean rofi_theme_parse_string(const char *string)
gboolean rofi_theme_parse_file(const char *file)
ThemeWidget * rofi_theme
Definition: theme.h:93
gboolean display_late_setup(void)
Definition: xcb.c:1714
void display_early_cleanup(void)
Definition: xcb.c:1749
void display_cleanup(void)
Definition: xcb.c:1755
gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings)
Definition: xcb.c:1491
void display_dump_monitor_layout(void)
Definition: xcb.c:685
ThemeWidget * rofi_configuration
Definition: xrmoptions.c:46