rofi  1.7.3
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-2021 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 "dialogs/dialogs.h"
63 #include "helper.h"
64 #include "mode.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 
88 static void rofi_collect_modi_destroy(void);
89 void rofi_add_error_message(GString *str) {
90  list_of_error_msgs = g_list_append(list_of_error_msgs, str);
91 }
93  if (list_of_error_msgs) {
94  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
95  iter = g_list_next(iter)) {
96  g_string_free((GString *)iter->data, TRUE);
97  }
98  g_list_free(list_of_error_msgs);
99  list_of_error_msgs = NULL;
100  }
101 }
102 
104 G_MODULE_EXPORT char *config_path = NULL;
107 Mode **modi = NULL;
108 
112 unsigned int num_available_modi = 0;
114 unsigned int num_modi = 0;
116 unsigned int curr_mode = 0;
117 
119 NkBindings *bindings = NULL;
120 
122 GMainLoop *main_loop = NULL;
123 
125 static int dmenu_mode = FALSE;
127 int return_code = EXIT_SUCCESS;
128 
129 void process_result(RofiViewState *state);
130 
131 void rofi_set_return_code(int code) { return_code = code; }
132 
133 unsigned int rofi_get_num_enabled_modi(void) { return num_modi; }
134 
135 const Mode *rofi_get_mode(unsigned int index) { return modi[index]; }
136 
144 static int mode_lookup(const char *name) {
145  for (unsigned int i = 0; i < num_modi; i++) {
146  if (strcmp(mode_get_name(modi[i]), name) == 0) {
147  return i;
148  }
149  }
150  return -1;
151 }
152 
156 static void teardown(int pfd) {
157  g_debug("Teardown");
158  // Cleanup font setup.
159  textbox_cleanup();
160 
162 
163  // Cleanup view
165  // Cleanup pid file.
166  remove_pid_file(pfd);
167 }
168 static void run_mode_index(ModeMode mode) {
169  // Otherwise check if requested mode is enabled.
170  for (unsigned int i = 0; i < num_modi; i++) {
171  if (!mode_init(modi[i])) {
172  GString *str = g_string_new("Failed to initialize the mode: ");
173  g_string_append(str, modi[i]->name);
174  g_string_append(str, "\n");
175 
177  g_string_free(str, FALSE);
178  break;
179  }
180  }
181  // Error dialog must have been created.
182  if (rofi_view_get_active() != NULL) {
183  return;
184  }
185  curr_mode = mode;
186  RofiViewState *state =
188 
189  // User can pre-select a row.
190  if (find_arg("-selected-row") >= 0) {
191  unsigned int sr = 0;
192  find_arg_uint("-selected-row", &(sr));
193  rofi_view_set_selected_line(state, sr);
194  }
195  if (state) {
196  rofi_view_set_active(state);
197  }
198  if (rofi_view_get_active() == NULL) {
199  g_main_loop_quit(main_loop);
200  }
201 }
203  Mode *sw = state->sw;
204  // rofi_view_set_active ( NULL );
205  if (sw != NULL) {
206  unsigned int selected_line = rofi_view_get_selected_line(state);
207  ;
208  MenuReturn mretv = rofi_view_get_return_value(state);
209  char *input = g_strdup(rofi_view_get_user_input(state));
210  ModeMode retv = mode_result(sw, mretv, &input, selected_line);
211  {
212  if (state->text) {
213  if (input == NULL) {
214  textbox_text(state->text, "");
215  } else if (strcmp(rofi_view_get_user_input(state), input) != 0) {
216  textbox_text(state->text, input);
217  textbox_cursor_end(state->text);
218  }
219  }
220  }
221  g_free(input);
222 
223  ModeMode mode = curr_mode;
224  // Find next enabled
225  if (retv == NEXT_DIALOG) {
226  mode = (mode + 1) % num_modi;
227  } else if (retv == PREVIOUS_DIALOG) {
228  if (mode == 0) {
229  mode = num_modi - 1;
230  } else {
231  mode = (mode - 1) % num_modi;
232  }
233  } else if (retv == RELOAD_DIALOG) {
234  // do nothing.
235  } else if (retv == RESET_DIALOG) {
236  rofi_view_clear_input(state);
237  } else if (retv < MODE_EXIT) {
238  mode = (retv) % num_modi;
239  } else {
240  mode = retv;
241  }
242  if (mode != MODE_EXIT) {
246  rofi_view_switch_mode(state, modi[mode]);
247  curr_mode = mode;
248  return;
249  }
250  // On exit, free current view, and pop to one above.
252  rofi_view_free(state);
253  return;
254  }
255  // rofi_view_set_active ( NULL );
257  rofi_view_free(state);
258 }
259 
263 static void print_list_of_modi(int is_term) {
264  for (unsigned int i = 0; i < num_available_modi; i++) {
265  gboolean active = FALSE;
266  for (unsigned int j = 0; j < num_modi; j++) {
267  if (modi[j] == available_modi[i]) {
268  active = TRUE;
269  break;
270  }
271  }
272  printf(" • %s%s%s%s\n", active ? "+" : "",
273  is_term ? (active ? color_green : color_red) : "",
274  available_modi[i]->name, is_term ? color_reset : "");
275  }
276 }
277 static void print_main_application_options(int is_term) {
278  print_help_msg("-no-config", "",
279  "Do not load configuration, use default values.", NULL,
280  is_term);
281  print_help_msg("-v,-version", "", "Print the version number and exit.", NULL,
282  is_term);
283  print_help_msg("-dmenu", "", "Start in dmenu mode.", NULL, is_term);
284  print_help_msg("-display", "[string]", "X server to contact.", "${DISPLAY}",
285  is_term);
286  print_help_msg("-h,-help", "", "This help message.", NULL, is_term);
287  print_help_msg("-e", "[string]",
288  "Show a dialog displaying the passed message and exit.", NULL,
289  is_term);
290  print_help_msg("-markup", "", "Enable pango markup where possible.", NULL,
291  is_term);
292  print_help_msg("-normal-window", "",
293  "Behave as a normal window. (experimental)", NULL, is_term);
294  print_help_msg("-show", "[mode]",
295  "Show the mode 'mode' and exit. The mode has to be enabled.",
296  NULL, is_term);
297  print_help_msg("-no-lazy-grab", "",
298  "Disable lazy grab that, when fail to grab keyboard, does not "
299  "block but retry later.",
300  NULL, is_term);
301  print_help_msg("-no-plugins", "", "Disable loading of external plugins.",
302  NULL, is_term);
303  print_help_msg("-plugin-path", "",
304  "Directory used to search for rofi plugins. *DEPRECATED*",
305  NULL, is_term);
306  print_help_msg("-dump-config", "",
307  "Dump the current configuration in rasi format and exit.",
308  NULL, is_term);
309  print_help_msg("-dump-theme", "",
310  "Dump the current theme in rasi format and exit.", NULL,
311  is_term);
312 }
313 static void help(G_GNUC_UNUSED int argc, char **argv) {
314  int is_term = isatty(fileno(stdout));
315  printf("%s usage:\n", argv[0]);
316  printf("\t%s [-options ...]\n\n", argv[0]);
317  printf("Command line only options:\n");
319  printf("DMENU command line options:\n");
321  printf("Global options:\n");
322  print_options();
323  printf("\n");
325  printf("\n");
326  printf("Detected modi:\n");
327  print_list_of_modi(is_term);
328  printf("\n");
329  printf("Compile time options:\n");
330 #ifdef WINDOW_MODE
331  printf("\t• window %senabled%s\n", is_term ? color_green : "",
332  is_term ? color_reset : "");
333 #else
334  printf("\t• window %sdisabled%s\n", is_term ? color_red : "",
335  is_term ? color_reset : "");
336 #endif
337 #ifdef ENABLE_DRUN
338  printf("\t• drun %senabled%s\n", is_term ? color_green : "",
339  is_term ? color_reset : "");
340 #else
341  printf("\t• drun %sdisabled%s\n", is_term ? color_red : "",
342  is_term ? color_reset : "");
343 #endif
344 #ifdef ENABLE_GCOV
345  printf("\t• gcov %senabled%s\n", is_term ? color_green : "",
346  is_term ? color_reset : "");
347 #else
348  printf("\t• gcov %sdisabled%s\n", is_term ? color_red : "",
349  is_term ? color_reset : "");
350 #endif
351 #ifdef ENABLE_ASAN
352  printf("\t• asan %senabled%s\n", is_term ? color_green : "",
353  is_term ? color_reset : "");
354 #else
355  printf("\t• asan %sdisabled%s\n", is_term ? color_red : "",
356  is_term ? color_reset : "");
357 #endif
358  printf("\n");
359  printf("For more information see: %sman rofi%s\n", is_term ? color_bold : "",
360  is_term ? color_reset : "");
361 #ifdef GIT_VERSION
362  printf(" Version: %s" GIT_VERSION "%s\n",
363  is_term ? color_bold : "", is_term ? color_reset : "");
364 #else
365  printf(" Version: %s" VERSION "%s\n",
366  is_term ? color_bold : "", is_term ? color_reset : "");
367 #endif
368  printf(" Bugreports: %s" PACKAGE_BUGREPORT "%s\n",
369  is_term ? color_bold : "", is_term ? color_reset : "");
370  printf(" Support: %s" PACKAGE_URL "%s\n",
371  is_term ? color_bold : "", is_term ? color_reset : "");
372  printf(" %s#rofi @ libera.chat%s\n",
373  is_term ? color_bold : "", is_term ? color_reset : "");
374  if (find_arg("-no-config") < 0) {
375  if (config_path) {
376  printf(" Configuration file: %s%s%s\n", is_term ? color_bold : "",
377  config_path, is_term ? color_reset : "");
378  }
379  } else {
380  printf(" Configuration file: %sDisabled%s\n",
381  is_term ? color_bold : "", is_term ? color_reset : "");
382  }
384 }
385 
386 static void help_print_disabled_mode(const char *mode) {
387  int is_term = isatty(fileno(stdout));
388  // Only output to terminal
389  if (is_term) {
390  fprintf(stderr, "Mode %s%s%s is not enabled. I have enabled it for now.\n",
391  color_red, mode, color_reset);
392  fprintf(stderr,
393  "Please consider adding %s%s%s to the list of enabled modi: "
394  "%smodi: [%s%s%s,%s]%s.\n",
396  color_red, mode, color_reset);
397  }
398 }
399 static void help_print_mode_not_found(const char *mode) {
400  GString *str = g_string_new("");
401  g_string_printf(str, "Mode %s is not found.\nThe following modi are known:\n",
402  mode);
403  for (unsigned int i = 0; i < num_available_modi; i++) {
404  gboolean active = FALSE;
405  for (unsigned int j = 0; j < num_modi; j++) {
406  if (modi[j] == available_modi[i]) {
407  active = TRUE;
408  break;
409  }
410  }
411  g_string_append_printf(str, " * %s%s\n", active ? "+" : "",
412  available_modi[i]->name);
413  }
415 }
416 static void help_print_no_arguments(void) {
417  int is_term = isatty(fileno(stdout));
418  // Daemon mode
419  fprintf(stderr, "Rofi is unsure what to show.\n");
420  fprintf(stderr, "Please specify the mode you want to show.\n\n");
421  fprintf(stderr, " %srofi%s -show %s{mode}%s\n\n",
422  is_term ? color_bold : "", is_term ? color_reset : "",
423  is_term ? color_green : "", is_term ? color_reset : "");
424  fprintf(stderr, "The following modi are enabled:\n");
425  for (unsigned int j = 0; j < num_modi; j++) {
426  fprintf(stderr, " * %s%s%s\n", is_term ? color_green : "", modi[j]->name,
427  is_term ? color_reset : "");
428  }
429  fprintf(stderr, "\nThe following can be enabled:\n");
430  for (unsigned int i = 0; i < num_available_modi; i++) {
431  gboolean active = FALSE;
432  for (unsigned int j = 0; j < num_modi; j++) {
433  if (modi[j] == available_modi[i]) {
434  active = TRUE;
435  break;
436  }
437  }
438  if (!active) {
439  fprintf(stderr, " * %s%s%s\n", is_term ? color_red : "",
440  available_modi[i]->name, is_term ? color_reset : "");
441  }
442  }
443  fprintf(stderr,
444  "\nTo activate a mode, add it to the list of modi in the %smodi%s "
445  "setting.\n",
446  is_term ? color_green : "", is_term ? color_reset : "");
447 }
448 
452 static void cleanup(void) {
453  for (unsigned int i = 0; i < num_modi; i++) {
454  mode_destroy(modi[i]);
455  }
457  if (main_loop != NULL) {
458  g_main_loop_unref(main_loop);
459  main_loop = NULL;
460  }
461  // Cleanup
462  display_cleanup();
463 
464  nk_bindings_free(bindings);
465 
466  // Cleaning up memory allocated by the Xresources file.
468  g_free(modi);
469 
470  g_free(config_path);
471 
473 
474  if (rofi_theme) {
476  rofi_theme = NULL;
477  }
478  TIMINGS_STOP();
481 
483  if (rofi_configuration) {
485  rofi_configuration = NULL;
486  }
487 }
488 
493 Mode *rofi_collect_modi_search(const char *name) {
494  for (unsigned int i = 0; i < num_available_modi; i++) {
495  if (g_strcmp0(name, available_modi[i]->name) == 0) {
496  return available_modi[i];
497  }
498  }
499  return NULL;
500 }
506 static gboolean rofi_collect_modi_add(Mode *mode) {
507  Mode *m = rofi_collect_modi_search(mode->name);
508  if (m == NULL) {
510  g_realloc(available_modi, sizeof(Mode *) * (num_available_modi + 1));
511  // Set mode.
514  return TRUE;
515  }
516  return FALSE;
517 }
518 
519 static void rofi_collect_modi_dir(const char *base_dir) {
520  g_debug("Looking into: %s for plugins", base_dir);
521  GDir *dir = g_dir_open(base_dir, 0, NULL);
522  if (dir) {
523  const char *dn = NULL;
524  while ((dn = g_dir_read_name(dir))) {
525  if (!g_str_has_suffix(dn, G_MODULE_SUFFIX)) {
526  continue;
527  }
528  char *fn = g_build_filename(base_dir, dn, NULL);
529  g_debug("Trying to open: %s plugin", fn);
530  GModule *mod =
531  g_module_open(fn, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
532  if (mod) {
533  Mode *m = NULL;
534  if (g_module_symbol(mod, "mode", (gpointer *)&m)) {
535  if (m->abi_version != ABI_VERSION) {
536  g_warning("ABI version of plugin: '%s' does not match: %08X "
537  "expecting: %08X",
538  dn, m->abi_version, ABI_VERSION);
539  g_module_close(mod);
540  } else {
541  m->module = mod;
542  if (!rofi_collect_modi_add(m)) {
543  g_module_close(mod);
544  }
545  }
546  } else {
547  g_warning("Symbol 'mode' not found in module: %s", dn);
548  g_module_close(mod);
549  }
550  } else {
551  g_warning("Failed to open 'mode' plugin: '%s', error: %s", dn,
552  g_module_error());
553  }
554  g_free(fn);
555  }
556  g_dir_close(dir);
557  }
558 }
559 
563 static void rofi_collect_modi(void) {
564 #ifdef WINDOW_MODE
565  rofi_collect_modi_add(&window_mode);
566  rofi_collect_modi_add(&window_mode_cd);
567 #endif
570 #ifdef ENABLE_DRUN
572 #endif
576 
577  if (find_arg("-no-plugins") < 0) {
578  find_arg_str("-plugin-path", &(config.plugin_path));
579  g_debug("Parse plugin path: %s", config.plugin_path);
581  /* ROFI_PLUGIN_PATH */
582  const char *path = g_getenv("ROFI_PLUGIN_PATH");
583  if (path != NULL) {
584  gchar **paths = g_strsplit(path, ":", -1);
585  for (unsigned int i = 0; paths[i]; i++) {
586  rofi_collect_modi_dir(paths[i]);
587  }
588  g_strfreev(paths);
589  }
590  }
591 }
592 
596 static void rofi_collect_modi_setup(void) {
597  for (unsigned int i = 0; i < num_available_modi; i++) {
599  }
600 }
601 static void rofi_collect_modi_destroy(void) {
602  for (unsigned int i = 0; i < num_available_modi; i++) {
603  if (available_modi[i]->module) {
604  GModule *mod = available_modi[i]->module;
605  available_modi[i] = NULL;
606  g_module_close(mod);
607  }
608  if (available_modi[i]) {
609  mode_free(&(available_modi[i]));
610  }
611  }
612  g_free(available_modi);
613  available_modi = NULL;
614  num_available_modi = 0;
615 }
616 
624 static int add_mode(const char *token) {
625  unsigned int index = num_modi;
626  // Resize and add entry.
627  modi = (Mode **)g_realloc(modi, sizeof(Mode *) * (num_modi + 1));
628 
629  Mode *mode = rofi_collect_modi_search(token);
630  if (mode) {
631  modi[num_modi] = mode;
632  num_modi++;
633  } else if (script_mode_is_valid(token)) {
634  // If not build in, use custom modi.
635  Mode *sw = script_mode_parse_setup(token);
636  if (sw != NULL) {
637  // Add to available list, so combi can find it.
639  mode_set_config(sw);
640  modi[num_modi] = sw;
641  num_modi++;
642  }
643  }
644  return (index == num_modi) ? -1 : (int)index;
645 }
646 static gboolean setup_modi(void) {
647  const char *const sep = ",#";
648  char *savept = NULL;
649  // Make a copy, as strtok will modify it.
650  char *mode_str = g_strdup(config.modi);
651  // Split token on ','. This modifies mode_str.
652  for (char *token = strtok_r(mode_str, sep, &savept); token != NULL;
653  token = strtok_r(NULL, sep, &savept)) {
654  if (add_mode(token) == -1) {
656  }
657  }
658  // Free string that was modified by strtok_r
659  g_free(mode_str);
660  return FALSE;
661 }
662 
667 void rofi_quit_main_loop(void) { g_main_loop_quit(main_loop); }
668 
669 static gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data) {
670  // Break out of loop.
671  g_main_loop_quit(main_loop);
672  return G_SOURCE_CONTINUE;
673 }
674 static void show_error_dialog(void) {
675  GString *emesg =
676  g_string_new("The following errors were detected when starting rofi:\n");
677  GList *iter = g_list_first(list_of_error_msgs);
678  int index = 0;
679  for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
680  GString *msg = (GString *)(iter->data);
681  g_string_append(emesg, "\n\n");
682  g_string_append(emesg, msg->str);
683  index++;
684  }
685  if (g_list_length(iter) > 1) {
686  g_string_append_printf(emesg, "\nThere are <b>%u</b> more errors.",
687  g_list_length(iter) - 1);
688  }
690  g_string_free(emesg, TRUE);
691  rofi_set_return_code(EX_DATAERR);
692 }
693 
694 static gboolean startup(G_GNUC_UNUSED gpointer data) {
695  TICK_N("Startup");
696  // flags to run immediately and exit
697  char *sname = NULL;
698  char *msg = NULL;
699  MenuFlags window_flags = MENU_NORMAL;
700 
701  if (find_arg("-normal-window") >= 0) {
702  window_flags |= MENU_NORMAL_WINDOW;
703  }
704  TICK_N("Grab keyboard");
705  __create_window(window_flags);
706  TICK_N("Create Window");
707  // Parse the keybindings.
708  TICK_N("Parse ABE");
709  // Sanity check
711  TICK_N("Config sanity check");
712 
713  if (list_of_error_msgs != NULL) {
715  return G_SOURCE_REMOVE;
716  }
717  // Dmenu mode.
718  if (dmenu_mode == TRUE) {
719  // force off sidebar mode:
720  config.sidebar_mode = FALSE;
721  int retv = dmenu_mode_dialog();
722  if (retv) {
723  rofi_set_return_code(EXIT_SUCCESS);
724  // Directly exit.
725  g_main_loop_quit(main_loop);
726  }
727  } else if (find_arg_str("-e", &(msg))) {
728  int markup = FALSE;
729  if (find_arg("-markup") >= 0) {
730  markup = TRUE;
731  }
732  if (!rofi_view_error_dialog(msg, markup)) {
733  g_main_loop_quit(main_loop);
734  }
735  } else if (find_arg_str("-show", &sname) == TRUE) {
736  int index = mode_lookup(sname);
737  if (index < 0) {
738  // Add it to the list
739  index = add_mode(sname);
740  // Complain
741  if (index >= 0) {
743  }
744  // Run it anyway if found.
745  }
746  if (index >= 0) {
747  run_mode_index(index);
748  } else {
751  return G_SOURCE_REMOVE;
752  }
753  } else if (find_arg("-show") >= 0 && num_modi > 0) {
754  run_mode_index(0);
755  } else {
757 
758  g_main_loop_quit(main_loop);
759  }
760 
761  return G_SOURCE_REMOVE;
762 }
763 
764 static gboolean record(G_GNUC_UNUSED void *data) {
766  return G_SOURCE_CONTINUE;
767 }
776 int main(int argc, char *argv[]) {
777  TIMINGS_START();
778 
779  cmd_set_arguments(argc, argv);
780 
781  // Version
782  if (find_arg("-v") >= 0 || find_arg("-version") >= 0) {
783 #ifdef GIT_VERSION
784  g_print("Version: " GIT_VERSION "\n");
785 #else
786  g_print("Version: " VERSION "\n");
787 #endif
788  return EXIT_SUCCESS;
789  }
790 
791  if (find_arg("-rasi-validate") >= 0) {
792  char *str = NULL;
793  find_arg_str("-rasi-validate", &str);
794  if (str != NULL) {
795  int retv = rofi_theme_rasi_validate(str);
796  cleanup();
797  return retv;
798  }
799  fprintf(stderr, "Usage: %s -rasi-validate my-theme.rasi", argv[0]);
800  return EXIT_FAILURE;
801  }
802 
803  {
804  const char *ro_pid = g_getenv("ROFI_OUTSIDE");
805  if (ro_pid != NULL) {
806  pid_t ro_pidi = (pid_t)g_ascii_strtoll(ro_pid, NULL, 0);
807  if (kill(ro_pidi, 0) == 0) {
808  printf("Do not launch rofi from inside rofi.\r\n");
809  return EXIT_FAILURE;
810  }
811  }
812  }
813 
814  // Detect if we are in dmenu mode.
815  // This has two possible causes.
816  // 1 the user specifies it on the command-line.
817  if (find_arg("-dmenu") >= 0) {
818  dmenu_mode = TRUE;
819  }
820  // 2 the binary that executed is called dmenu (e.g. symlink to rofi)
821  else {
822  // Get the base name of the executable called.
823  char *base_name = g_path_get_basename(argv[0]);
824  const char *const dmenu_str = "dmenu";
825  dmenu_mode = (strcmp(base_name, dmenu_str) == 0);
826  // Free the basename for dmenu detection.
827  g_free(base_name);
828  }
829  TICK();
830 
831  // Create pid file path.
832  const char *path = g_get_user_runtime_dir();
833  if (path) {
834  if (g_mkdir_with_parents(path, 0700) < 0) {
835  g_warning("Failed to create user runtime directory: %s with error: %s",
836  path, g_strerror(errno));
837  pidfile = g_build_filename(g_get_home_dir(), ".rofi.pid", NULL);
838  } else {
839  pidfile = g_build_filename(path, "rofi.pid", NULL);
840  }
841  }
842  config_parser_add_option(xrm_String, "pid", (void **)&pidfile,
843  "Pidfile location");
844 
846  if (find_arg("-no-default-config") < 0) {
847  GBytes *theme_data = g_resource_lookup_data(
848  resources_get_resource(), "/org/qtools/rofi/default_configuration.rasi",
849  G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
850  if (theme_data) {
851  const char *theme = g_bytes_get_data(theme_data, NULL);
852  if (rofi_theme_parse_string((const char *)theme)) {
853  g_warning("Failed to parse default configuration. Giving up..");
854  if (list_of_error_msgs) {
855  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
856  iter = g_list_next(iter)) {
857  g_warning("Error: %s%s%s", color_bold, ((GString *)iter->data)->str,
858  color_reset);
859  }
860  }
861  rofi_configuration = NULL;
862  cleanup();
863  return EXIT_FAILURE;
864  }
865  g_bytes_unref(theme_data);
866  }
867  }
868 
869  if (find_arg("-config") < 0) {
870  const char *cpath = g_get_user_config_dir();
871  if (cpath) {
872  config_path = g_build_filename(cpath, "rofi", "config.rasi", NULL);
873  }
874  } else {
875  char *c = NULL;
876  find_arg_str("-config", &c);
878  }
879 
880  TICK();
881  if (setlocale(LC_ALL, "") == NULL) {
882  g_warning("Failed to set locale.");
883  cleanup();
884  return EXIT_FAILURE;
885  }
886 
887  TICK_N("Setup Locale");
889  TICK_N("Collect MODI");
891  TICK_N("Setup MODI");
892 
893  main_loop = g_main_loop_new(NULL, FALSE);
894 
895  TICK_N("Setup mainloop");
896 
897  bindings = nk_bindings_new(0lu);
898  TICK_N("NK Bindings");
899 
901  g_warning("Connection has error");
902  cleanup();
903  return EXIT_FAILURE;
904  }
905  TICK_N("Setup Display");
906 
907  // Setup keybinding
908  setup_abe();
909  TICK_N("Setup abe");
910 
911  if (find_arg("-no-config") < 0) {
912  // Load distro default settings
913  gboolean found_system = FALSE;
914  const char *const *dirs = g_get_system_config_dirs();
915  if (dirs) {
916  for (unsigned int i = 0; !found_system && dirs[i]; i++) {
918  gchar *etc = g_build_filename(dirs[i], "rofi.rasi", NULL);
919  g_debug("Look for default config file: %s", etc);
920  if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
921  g_debug("Parsing: %s", etc);
923  found_system = TRUE;
924  }
925  g_free(etc);
926  }
927  }
928  if (!found_system) {
930  gchar *etc = g_build_filename(SYSCONFDIR, "rofi.rasi", NULL);
931  g_debug("Look for default config file: %s", etc);
932  if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
933  g_debug("Look for default config file: %s", etc);
935  }
936  g_free(etc);
937  }
938 
939  if (config_path && g_file_test(config_path, G_FILE_TEST_IS_REGULAR)) {
942  rofi_theme = NULL;
943  }
944  }
945  }
946  find_arg_str("-theme", &(config.theme));
947  if (config.theme) {
948  TICK_N("Parse theme");
951  g_warning("Failed to parse theme: \"%s\"", config.theme);
952  // TODO: instantiate fallback theme.?
954  rofi_theme = NULL;
955  }
956  TICK_N("Parsed theme");
957  }
958  // Parse command line for settings, independent of other -no-config.
959  if (list_of_error_msgs == NULL) {
960  // Only call this when there are no errors.
961  // This might clear existing errors.
963  }
964  TICK_N("Load cmd config ");
965 
966  // Get the path to the cache dir.
967  cache_dir = g_get_user_cache_dir();
968 
969  if (config.cache_dir != NULL) {
971  }
972 
973  if (g_mkdir_with_parents(cache_dir, 0700) < 0) {
974  g_warning("Failed to create cache directory: %s", g_strerror(errno));
975  return EXIT_FAILURE;
976  }
977 
979  char *windowid = NULL;
980  if (!dmenu_mode) {
981  // setup_modi
982  if (setup_modi()) {
983  cleanup();
984  return EXIT_FAILURE;
985  }
986  TICK_N("Setup Modi");
987  } else {
988  // Hack for dmenu compatibility.
989  if (find_arg_str("-w", &windowid) == TRUE) {
990  config.monitor = g_strdup_printf("wid:%s", windowid);
991  windowid = config.monitor;
992  }
993  }
994 
998  const char **theme_str = find_arg_strv("-theme-str");
999  if (theme_str) {
1000  for (int index = 0; theme_str && theme_str[index]; index++) {
1001  if (rofi_theme_parse_string(theme_str[index])) {
1002  g_warning("Failed to parse -theme-str option: \"%s\"",
1003  theme_str[index]);
1005  rofi_theme = NULL;
1006  }
1007  }
1008  g_free(theme_str);
1009  }
1010 
1012  if (find_arg("-dump-theme") >= 0) {
1014  cleanup();
1015  return EXIT_SUCCESS;
1016  }
1017  if (find_arg("-dump-processed-theme") >= 0) {
1020  cleanup();
1021  return EXIT_SUCCESS;
1022  }
1023  if (find_arg("-dump-config") >= 0) {
1024  config_parse_dump_config_rasi_format(stdout, FALSE);
1025  cleanup();
1026  return EXIT_SUCCESS;
1027  }
1028  // Dump.
1029  // catch help request
1030  if (find_arg("-h") >= 0 || find_arg("-help") >= 0 ||
1031  find_arg("--help") >= 0) {
1032  help(argc, argv);
1033  cleanup();
1034  return EXIT_SUCCESS;
1035  }
1036 
1037  unsigned int interval = 1;
1038  if (find_arg_uint("-record-screenshots", &interval)) {
1039  g_timeout_add((guint)(1000 / (double)interval), record, NULL);
1040  }
1041  if (find_arg("-benchmark-ui") >= 0) {
1042  config.benchmark_ui = TRUE;
1043  }
1044 
1046  TICK_N("Workers initialize");
1048  TICK_N("Icon fetcher initialize");
1049 
1050  gboolean kill_running = FALSE;
1051  if (find_arg("-replace") >= 0) {
1052  kill_running = TRUE;
1053  }
1054  // Create pid file
1055  int pfd = create_pid_file(pidfile, kill_running);
1056  TICK_N("Pid file created");
1057  if (pfd < 0) {
1058  cleanup();
1059  return EXIT_FAILURE;
1060  }
1061  textbox_setup();
1062  TICK_N("Text box setup");
1063 
1064  if (!display_late_setup()) {
1065  g_warning("Failed to properly finish display setup");
1066  cleanup();
1067  return EXIT_FAILURE;
1068  }
1069  TICK_N("Setup late Display");
1070 
1072  TICK_N("Theme setup");
1073 
1074  // Setup signal handling sources.
1075  // SIGINT
1076  g_unix_signal_add(SIGINT, main_loop_signal_handler_int, NULL);
1077 
1078  g_idle_add(startup, NULL);
1079 
1080  // Start mainloop.
1081  g_main_loop_run(main_loop);
1082  teardown(pfd);
1083  cleanup();
1084 
1085  /* dirty hack */
1086  g_free(windowid);
1087  return return_code;
1088 }
1089 
1091 extern GList *list_of_error_msgs;
1092 int rofi_theme_rasi_validate(const char *filename) {
1093  rofi_theme_parse_file(filename);
1094  if (list_of_error_msgs == NULL) {
1095  return EXIT_SUCCESS;
1096  }
1097 
1098  for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
1099  iter = g_list_next(iter)) {
1100  fputs(((GString *)iter->data)->str, stderr);
1101  }
1102 
1103  return EXIT_FAILURE;
1104 }
Mode drun_mode
Definition: drun.c:1475
Mode combi_mode
Definition: combi.c:327
void config_parse_cmd_options(void)
Definition: xrmoptions.c:533
void print_options(void)
Definition: xrmoptions.c:929
void config_parser_add_option(XrmOptionType type, const char *key, void **value, const char *comment)
Definition: xrmoptions.c:428
void print_help_msg(const char *option, const char *type, const char *text, const char *def, int isatty)
Definition: xrmoptions.c:946
void config_parse_dump_config_rasi_format(FILE *out, gboolean changes)
Dump configuration in rasi format.
Definition: xrmoptions.c:791
@ xrm_String
Definition: xrmoptions.h:74
void config_xresource_free(void)
Definition: xrmoptions.c:729
int dmenu_mode_dialog(void)
Definition: dmenu.c:679
void print_dmenu_options(void)
Definition: dmenu.c:777
Mode file_browser_mode
Definition: filebrowser.c:651
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:597
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
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 config_sanity_check(void)
Definition: helper.c:624
int create_pid_file(const char *pidfile, gboolean kill_running)
Definition: helper.c:539
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:167
void setup_abe(void)
Definition: keyb.c:136
void mode_destroy(Mode *mode)
Definition: mode.c:48
int mode_init(Mode *mode)
Definition: mode.c:42
void mode_free(Mode **mode)
Definition: mode.c:122
ModeMode mode_result(Mode *mode, int menu_retv, char **input, unsigned int selected_line)
Definition: mode.c:91
MenuReturn
Definition: mode.h:65
ModeMode
Definition: mode.h:49
const char * mode_get_name(const Mode *mode)
Definition: mode.c:117
void mode_set_config(Mode *mode)
Definition: mode.c:160
@ 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:667
#define color_reset
Definition: rofi.h:95
#define color_bold
Definition: rofi.h:97
Mode * rofi_collect_modi_search(const char *name)
Definition: rofi.c:493
void rofi_clear_error_messages(void)
Definition: rofi.c:92
#define color_red
Definition: rofi.h:103
#define ERROR_MSG_MARKUP
Definition: rofi.h:116
void rofi_set_return_code(int code)
Definition: rofi.c:131
unsigned int rofi_get_num_enabled_modi(void)
Definition: rofi.c:133
const Mode * rofi_get_mode(unsigned int index)
Definition: rofi.c:135
const char * cache_dir
Definition: rofi.c:83
void rofi_add_error_message(GString *str)
Definition: rofi.c:89
#define color_green
Definition: rofi.h:101
Mode run_mode
Definition: run.c:575
Mode * script_mode_parse_setup(const char *str)
Definition: script.c:425
gboolean script_mode_is_valid(const char *token)
Definition: script.c:463
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:870
void textbox_setup(void)
Definition: textbox.c:844
void textbox_cursor_end(textbox *tb)
Definition: textbox.c:623
void textbox_text(textbox *tb, const char *text)
Definition: textbox.c:345
void rofi_view_cleanup()
Definition: view.c:2127
void __create_window(MenuFlags menu_flags)
Definition: view.c:755
void rofi_view_clear_input(RofiViewState *state)
Definition: view.c:2218
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
Definition: view.c:2229
void rofi_view_remove_active(RofiViewState *state)
Definition: view.c:524
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
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
@ MENU_NORMAL_WINDOW
Definition: view.h:54
@ MENU_NORMAL
Definition: view.h:50
void rofi_capture_screenshot(void)
Definition: view.c:174
void rofi_view_workers_initialize(void)
Definition: view.c:2169
void rofi_view_workers_finalize(void)
Definition: view.c:2196
#define ABI_VERSION
Definition: mode-private.h:34
static void help(G_GNUC_UNUSED int argc, char **argv)
Definition: rofi.c:313
static void rofi_collect_modi_setup(void)
Definition: rofi.c:596
static void rofi_collect_modi_destroy(void)
Definition: rofi.c:601
int main(int argc, char *argv[])
Definition: rofi.c:776
GList * list_of_error_msgs
Definition: rofi.c:86
static gboolean record(G_GNUC_UNUSED void *data)
Definition: rofi.c:764
unsigned int num_modi
Definition: rofi.c:114
G_MODULE_EXPORT char * config_path
Definition: rofi.c:104
NkBindings * bindings
Definition: rofi.c:119
Mode ** available_modi
Definition: rofi.c:110
static void print_main_application_options(int is_term)
Definition: rofi.c:277
static void run_mode_index(ModeMode mode)
Definition: rofi.c:168
static void help_print_mode_not_found(const char *mode)
Definition: rofi.c:399
static void cleanup(void)
Definition: rofi.c:452
static void print_list_of_modi(int is_term)
Definition: rofi.c:263
static void rofi_collect_modi_dir(const char *base_dir)
Definition: rofi.c:519
static gboolean startup(G_GNUC_UNUSED gpointer data)
Definition: rofi.c:694
static void rofi_collect_modi(void)
Definition: rofi.c:563
int rofi_theme_rasi_validate(const char *filename)
Definition: rofi.c:1092
GMainLoop * main_loop
Definition: rofi.c:122
static void teardown(int pfd)
Definition: rofi.c:156
char * pidfile
Definition: rofi.c:81
int return_code
Definition: rofi.c:127
void process_result(RofiViewState *state)
Definition: rofi.c:202
unsigned int num_available_modi
Definition: rofi.c:112
static int add_mode(const char *token)
Definition: rofi.c:624
static gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data)
Definition: rofi.c:669
static gboolean setup_modi(void)
Definition: rofi.c:646
static void show_error_dialog(void)
Definition: rofi.c:674
Mode ** modi
Definition: rofi.c:107
static void help_print_no_arguments(void)
Definition: rofi.c:416
static int dmenu_mode
Definition: rofi.c:125
static int mode_lookup(const char *name)
Definition: rofi.c:144
static void help_print_disabled_mode(const char *mode)
Definition: rofi.c:386
static gboolean rofi_collect_modi_add(Mode *mode)
Definition: rofi.c:506
unsigned int curr_mode
Definition: rofi.c:116
Settings config
textbox * text
Definition: view-internal.h:59
char * cache_dir
Definition: settings.h:163
char * theme
Definition: settings.h:150
char * plugin_path
Definition: settings.h:152
char * filter
Definition: settings.h:139
char * modi
Definition: settings.h:57
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_conditionals(void)
Definition: theme.c:1545
void rofi_theme_print(ThemeWidget *widget)
Definition: theme.c:573
void rofi_theme_reset(void)
Definition: theme.c:225
void rofi_theme_free(ThemeWidget *widget)
Definition: theme.c:231
gboolean rofi_theme_parse_string(const char *string)
gboolean rofi_theme_parse_file(const char *file)
ThemeWidget * rofi_theme
Definition: theme.h:90
gboolean display_late_setup(void)
Definition: xcb.c:1689
void display_early_cleanup(void)
Definition: xcb.c:1724
void display_cleanup(void)
Definition: xcb.c:1730
gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings)
Definition: xcb.c:1466
void display_dump_monitor_layout(void)
Definition: xcb.c:666
ThemeWidget * rofi_configuration
Definition: xrmoptions.c:46