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
81char *pidfile = NULL;
83const char *cache_dir = NULL;
84
86GList *list_of_error_msgs = NULL;
88
89static void rofi_collectmodes_destroy(void);
90void rofi_add_error_message(GString *str) {
91 list_of_error_msgs = g_list_append(list_of_error_msgs, str);
92}
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}
103void rofi_add_warning_message(GString *str) {
104 list_of_warning_msgs = g_list_append(list_of_warning_msgs, str);
105}
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);
114 }
115}
116
118G_MODULE_EXPORT char *config_path = NULL;
121Mode **modes = NULL;
122
126unsigned int num_available_modes = 0;
128unsigned int num_modes = 0;
130unsigned int curr_mode = 0;
131
133NkBindings *bindings = NULL;
134
136GMainLoop *main_loop = NULL;
137
139static int dmenu_mode = FALSE;
141int return_code = EXIT_SUCCESS;
142
143void process_result(RofiViewState *state);
144
145void rofi_set_return_code(int code) { return_code = code; }
146
147unsigned int rofi_get_num_enabled_modes(void) { return num_modes; }
148
149const Mode *rofi_get_mode(unsigned int index) { return modes[index]; }
150
158static 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
170static void teardown(int pfd) {
171 g_debug("Teardown");
172 // Cleanup font setup.
174
176
177 // Cleanup view
179
180 // Cleanup pid file.
181 remove_pid_file(pfd);
182}
183static 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));
209 }
210 if (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 ;
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) {
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
278static 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}
292static 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}
330static 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");
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
407static 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}
420static 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 ? "+" : "",
434 }
436}
437static 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
473static void cleanup(void) {
474 for (unsigned int i = 0; i < num_modes; i++) {
476 }
478 if (main_loop != NULL) {
479 g_main_loop_unref(main_loop);
480 main_loop = NULL;
481 }
482 // 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
516Mode *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}
529static gboolean rofi_collectmodes_add(Mode *mode) {
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
542static 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
586static 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
620static void rofi_collectmodes_setup(void) {
621 for (unsigned int i = 0; i < num_available_modes; i++) {
623 }
624}
625static 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]) {
634 }
635 }
636 g_free(available_modes);
637 available_modes = NULL;
639}
640
648static 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}
670static 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
691void rofi_quit_main_loop(void) { g_main_loop_quit(main_loop); }
692
693static 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}
698static 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
718static 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) {
786 } else {
788
789 // g_main_loop_quit(main_loop);
790 }
791
792 return G_SOURCE_REMOVE;
793}
794
795static gboolean record(G_GNUC_UNUSED void *data) {
797 return G_SOURCE_CONTINUE;
798}
799static 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}
814int 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 }
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 }
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,
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");
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) {
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
1147extern GList *list_of_error_msgs;
1148int 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
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
char * rofi_expand_path(const char *input)
Definition helper.c:740
void remove_pid_file(int fd)
Definition helper.c:620
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
const char * mode_get_name(const Mode *mode)
Definition mode.c:145
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
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
const Mode * rofi_get_mode(unsigned int index)
Definition rofi.c:149
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
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
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 * script_mode_parse_setup(const char *str)
Definition script.c:519
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
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
RofiViewState * rofi_view_get_active(void)
Definition view.c:549
MenuFlags
Definition view.h:48
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
Definition view.c:617
const char * rofi_view_get_user_input(const RofiViewState *state)
Definition view.c:638
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
Definition view.c:581
void rofi_view_free(RofiViewState *state)
Definition view.c:599
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
Definition view.c:2103
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
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
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
GModule * module
char * name
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