31#define G_LOG_DOMAIN "Rofi"
48#ifdef USE_NK_GIT_VERSION
49#include "nkutils-git-version.h"
51#define GIT_VERSION NK_GIT_VERSION
76#include <wayland-version.h>
81#define ROFI_MAX_DMENU_INPUT UINT32_MAX
103 iter = g_list_next(iter)) {
104 g_string_free((GString *)iter->data, TRUE);
116 iter = g_list_next(iter)) {
117 g_string_free((GString *)iter->data, TRUE);
162 for (
unsigned int i = 0; i <
num_modes; i++) {
203 for (
unsigned int i = 0; i <
num_modes; i++) {
205 GString *str = g_string_new(
"Failed to initialize the mode: ");
207 g_string_append(str,
"\n");
210 g_string_free(str, FALSE);
223 if (
find_arg(
"-selected-row") >= 0) {
298 gboolean active = FALSE;
299 for (
unsigned int j = 0; j <
num_modes; j++) {
305 printf(
" • %s%s%s%s", active ?
"+" :
"",
309 printf(
" (external)");
315 print_help_msg(
"-config",
"[file]",
"Load an alternative configuration.",
318 "Do not load configuration, use default values.", NULL,
320 print_help_msg(
"-v,-version",
"",
"Print the version number and exit.", NULL,
322 print_help_msg(
"-dmenu",
"",
"Start in dmenu mode.", NULL, is_term);
323 print_help_msg(
"-display",
"[string]",
"X server to contact.",
"${DISPLAY}",
325 print_help_msg(
"-h,-help",
"",
"This help message.", NULL, is_term);
327 "Show a dialog displaying the passed message and exit.", NULL,
329 print_help_msg(
"-markup",
"",
"Enable pango markup where possible.", NULL,
332 "Behave as a normal window. (experimental)", NULL, is_term);
334 "Behave as a modal dialog that is transient to the currently "
335 "focused window. (experimental)",
338 "Show the mode 'mode' and exit. The mode has to be enabled.",
341 "Disable lazy grab that, when fail to grab keyboard, does not "
342 "block but retry later.",
344 print_help_msg(
"-no-plugins",
"",
"Disable loading of external plugins.",
347 "Directory used to search for rofi plugins. *DEPRECATED*",
350 "Dump the current configuration in rasi format and exit.",
353 "Dump the current theme in rasi format and exit.", NULL,
356 "Print a list of current keybindings and exit.", NULL,
361 int is_term = isatty(fileno(stdout));
362 printf(
"Display backends:\n");
366 printf(
": %sselected%s\n", is_term ?
color_bold :
"",
373 printf(
"\t• wayland");
375 printf(
": %sselected%s\n", is_term ?
color_bold :
"",
384static void help(G_GNUC_UNUSED
int argc,
char **argv,
const gboolean compact) {
385 int is_term = isatty(fileno(stdout));
386 const char *color_bold_str = is_term ?
color_bold :
"";
387 const char *color_reset_str = is_term ?
color_reset :
"";
389 printf(
"%s usage:\n", argv[0]);
390 printf(
"\t%s [-options ...]\n\n", argv[0]);
391 printf(
"Command line only options:\n");
393 printf(
"DMENU command line options:\n");
395 printf(
"Global options:\n");
403 printf(
"Detected Window manager:\n");
406 printf(
"\t• %s\n", wm);
409 printf(
"\t• No window manager detected.\n");
417 printf(
"Detected modes:\n");
420 printf(
"Detected user scripts:\n");
423 printf(
"Compile time options:\n");
424 printf(
"\t• Pango version %s\n", pango_version_string());
426 printf(
"\t• window %senabled%s\n", is_term ?
color_green :
"",
429 printf(
"\t• window %sdisabled%s\n", is_term ?
color_red :
"",
433 printf(
"\t• drun %senabled%s\n", is_term ?
color_green :
"",
436 printf(
"\t• drun %sdisabled%s\n", is_term ?
color_red :
"",
440 printf(
"\t• asan %senabled%s\n", is_term ?
color_green :
"",
443 printf(
"\t• asan %sdisabled%s\n", is_term ?
color_red :
"",
447 printf(
"\t• imdkit %senabled%s\n", is_term ?
color_green :
"",
450 printf(
"\t• imdkit %sdisabled%s\n", is_term ?
color_red :
"",
454 printf(
"\t• xcb %senabled%s\n", is_term ?
color_green :
"",
457 printf(
"\t• xcb %sdisabled%s\n", is_term ?
color_red :
"",
461 printf(
"\t• wayland %senabled%s (%s)\n", is_term ?
color_green :
"",
462 color_reset_str, WAYLAND_VERSION);
464 printf(
"\t• wayland %sdisabled%s\n", is_term ?
color_red :
"",
468 printf(
"For more information see: %sman rofi%s\n", color_bold_str,
471 printf(
" Version: %s" GIT_VERSION
"%s\n", color_bold_str,
474 printf(
" Version: %s" VERSION
"%s\n", color_bold_str,
477 printf(
" Bugreports: %s" PACKAGE_BUGREPORT
"%s\n",
478 color_bold_str, color_reset_str);
479 printf(
" Support: %s" PACKAGE_URL
"%s\n", color_bold_str,
481 printf(
" %s#rofi @ libera.chat%s\n", color_bold_str,
485 printf(
" Configuration file: %s%s%s\n", color_bold_str,
config_path,
489 printf(
" Configuration file: %sDisabled%s\n", color_bold_str,
495 printf(
"\nXDG Data directories\n");
497 const char *udd = g_get_user_data_dir();
498 printf(
"\t• %sXDG_DATA_HOME=%s\'%s\'\n", color_bold_str, color_reset_str,
500 const char *ucd = g_get_user_config_dir();
501 printf(
"\t• %sXDG_CONFIG_HOME=%s\'%s\'\n", color_bold_str, color_reset_str,
503 const char *ucad = g_get_user_cache_dir();
504 printf(
"\t• %sXDG_CACHE_HOME=%s\'%s\'\n", color_bold_str, color_reset_str,
507 const char *udesktopd = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
508 printf(
"\t• %sDesktop=%s\'%s\'\n", color_bold_str, color_reset_str,
510 const char *upicturesd = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
511 printf(
"\t• %spictures=%s\'%s\'\n", color_bold_str, color_reset_str,
513 printf(
"\n\tSystem:\n");
514 const char *
const *sdd = g_get_system_data_dirs();
515 printf(
"\t• %sXDG_DATA_DIRS=%s[", color_bold_str, color_reset_str);
516 for (
int i = 0; sdd && sdd[i]; i++) {
517 printf(
"\'%s\'", sdd[i]);
523 const char *
const *scd = g_get_system_config_dirs();
524 printf(
"\t• %sXDG_CONFIG_DIRS=%s[", color_bold_str, color_reset_str);
525 for (
int i = 0; scd && scd[i]; i++) {
526 printf(
"\'%s\'", scd[i]);
535 int is_term = isatty(fileno(stdout));
538 fprintf(stderr,
"Mode %s%s%s is not enabled. I have enabled it for now.\n",
541 "Please consider adding %s%s%s to the list of enabled modes: "
542 "%smodes: [%s%s%s,%s]%s.\n",
548 GString *str = g_string_new(
"");
550 str,
"Mode %s is not found.\nThe following modes are known:\n", mode);
552 gboolean active = FALSE;
553 for (
unsigned int j = 0; j <
num_modes; j++) {
559 g_string_append_printf(str,
" * %s%s\n", active ?
"+" :
"",
566 GString *emesg = g_string_new(
567 "<span size=\"x-large\">Rofi is unsure what to show.</span>\n\n");
568 g_string_append(emesg,
"Please specify the mode you want to show.\n\n");
570 emesg,
" <b>rofi</b> -show <span color=\"green\">{mode}</span>\n\n");
571 g_string_append(emesg,
"The following modes are enabled:\n");
572 for (
unsigned int j = 0; j <
num_modes; j++) {
573 g_string_append_printf(emesg,
" • <span color=\"green\">%s</span>\n",
576 g_string_append(emesg,
"\nThe following modes can be enabled:\n");
578 gboolean active = FALSE;
579 for (
unsigned int j = 0; j <
num_modes; j++) {
586 g_string_append_printf(emesg,
" • <span color=\"red\">%s</span>\n",
590 g_string_append(emesg,
"\nTo activate a mode, add it to the list in "
591 "the <span color=\"green\">modes</span> "
601 for (
unsigned int i = 0; i <
num_modes; i++) {
675 g_debug(
"Looking into: %s for plugins", base_dir);
676 GDir *dir = g_dir_open(base_dir, 0, NULL);
678 const char *dn = NULL;
679 while ((dn = g_dir_read_name(dir))) {
680 if (!g_str_has_suffix(dn, G_MODULE_SUFFIX)) {
683 char *fn = g_build_filename(base_dir, dn, NULL);
684 g_debug(
"Trying to open: %s plugin", fn);
686 g_module_open(fn, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
689 if (g_module_symbol(mod,
"mode", (gpointer *)&m)) {
691 g_warning(
"ABI version of plugin: '%s' does not match: %08X "
702 g_warning(
"Symbol 'mode' not found in module: %s", dn);
706 g_warning(
"Failed to open 'mode' plugin: '%s', error: %s", dn,
744 g_debug(
"Parse plugin path: %s",
config.plugin_path);
747 const char *path = g_getenv(
"ROFI_PLUGIN_PATH");
749 gchar **paths = g_strsplit(path,
":", -1);
750 for (
unsigned int i = 0; paths[i]; i++) {
810 return (index ==
num_modes) ? -1 : (int)index;
813 const char *
const sep =
",#";
816 char *mode_str = g_strdup(
config.modes);
818 for (
char *token = strtok_r(mode_str, sep, &savept); token != NULL;
819 token = strtok_r(NULL, sep, &savept)) {
838 return G_SOURCE_CONTINUE;
842 g_string_new(
"The following errors were detected when starting rofi:\n");
845 for (; iter != NULL && index < 2; iter = g_list_next(iter)) {
846 GString *msg = (GString *)(iter->data);
847 g_string_append(emesg,
"\n\n");
848 g_string_append(emesg, msg->str);
851 if (g_list_length(iter) > 1) {
852 g_string_append_printf(emesg,
"\nThere are <b>%u</b> more errors.",
853 g_list_length(iter) - 1);
856 g_string_free(emesg, TRUE);
860static gboolean
startup(G_GNUC_UNUSED gpointer data) {
867 if (
find_arg(
"-normal-window") >= 0) {
870 if (
find_arg(
"-transient-window") >= 0) {
880 TICK_N(
"Config sanity check");
884 return G_SOURCE_REMOVE;
888 iter = g_list_next(iter)) {
889 g_warning(((GString *)iter->data)->str, NULL);
897 config.sidebar_mode = FALSE;
910 if (g_strcmp0(msg,
"-") == 0) {
911 size_t index = 0, i = 0;
913 size_t length = 1025;
914 msg = g_malloc(length *
sizeof(
char));
915 while ((i = fread(&msg[index], 1, 1024, stdin)) > 0) {
921 msg = g_realloc(msg, length *
sizeof(
char));
952 return G_SOURCE_REMOVE;
962 return G_SOURCE_REMOVE;
968 return G_SOURCE_REMOVE;
970static gboolean
record(G_GNUC_UNUSED
void *data) {
972 return G_SOURCE_CONTINUE;
975 G_GNUC_UNUSED GLogLevelFlags log_level,
976 const gchar *message, gpointer user_data) {
977 int fp = GPOINTER_TO_INT(user_data);
978 dprintf(fp,
"[%s]: %s\n", log_domain == NULL ?
"default" : log_domain,
989int main(
int argc,
char *argv[]) {
992 char *logfile = NULL;
994 if (logfile != NULL) {
995 int fp = open(logfile, O_CLOEXEC | O_APPEND | O_CREAT | O_WRONLY,
999 GINT_TO_POINTER(fp));
1002 g_error(
"Failed to open logfile '%s': %s.", logfile, strerror(errno));
1006 g_warning(
"Option '-log' should pass in a filename.");
1014 g_print(
"Version: " GIT_VERSION
"\n");
1016 g_print(
"Version: " VERSION
"\n");
1018 return EXIT_SUCCESS;
1021 if (
find_arg(
"-rasi-validate") >= 0) {
1029 fprintf(stderr,
"Usage: %s -rasi-validate my-theme.rasi", argv[0]);
1030 return EXIT_FAILURE;
1034 const char *ro_pid = g_getenv(
"ROFI_OUTSIDE");
1035 if (ro_pid != NULL) {
1036 pid_t ro_pidi = (pid_t)g_ascii_strtoll(ro_pid, NULL, 0);
1037 if (kill(ro_pidi, 0) == 0) {
1038 printf(
"Do not launch rofi from inside rofi.\r\n");
1039 return EXIT_FAILURE;
1053 char *base_name = g_path_get_basename(argv[0]);
1054 const char *
const dmenu_str =
"dmenu";
1062 const char *path = g_get_user_runtime_dir();
1064 if (g_mkdir_with_parents(path, 0700) < 0) {
1065 g_warning(
"Failed to create user runtime directory: %s with error: %s",
1066 path, g_strerror(errno));
1067 pidfile = g_build_filename(g_get_home_dir(),
".rofi.pid", NULL);
1069 pidfile = g_build_filename(path,
"rofi.pid", NULL);
1073 "Pidfile location");
1076 if (
find_arg(
"-no-default-config") < 0) {
1077 GBytes *theme_data = g_resource_lookup_data(
1078 resources_get_resource(),
"/org/qtools/rofi/default_configuration.rasi",
1079 G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
1081 const char *theme = g_bytes_get_data(theme_data, NULL);
1083 g_warning(
"Failed to parse default configuration. Giving up..");
1086 iter = g_list_next(iter)) {
1087 g_warning(
"Error: %s%s%s",
color_bold, ((GString *)iter->data)->str,
1093 return EXIT_FAILURE;
1095 g_bytes_unref(theme_data);
1100 const char *cpath = g_get_user_config_dir();
1102 config_path = g_build_filename(cpath,
"rofi",
"config.rasi", NULL);
1117#ifdef ENABLE_WAYLAND
1119 const gchar *wl_display = g_getenv(
"WAYLAND_DISPLAY");
1121 strlen(wl_display) > 0) {
1133 if (setlocale(LC_ALL,
"") == NULL) {
1134 g_warning(
"Failed to set locale.");
1136 return EXIT_FAILURE;
1145 main_loop = g_main_loop_new(NULL, FALSE);
1147 TICK_N(
"Setup mainloop");
1158 gboolean found_system = FALSE;
1159 const char *
const *dirs = g_get_system_config_dirs();
1161 for (
unsigned int i = 0; !found_system && dirs[i]; i++) {
1163 gchar *etc = g_build_filename(dirs[i],
"rofi.rasi", NULL);
1164 g_debug(
"Look for default config file: %s", etc);
1165 if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
1166 g_debug(
"Parsing: %s", etc);
1168 found_system = TRUE;
1173 if (!found_system) {
1175 gchar *etc = g_build_filename(SYSCONFDIR,
"rofi.rasi", NULL);
1176 g_debug(
"Look for default config file: %s", etc);
1177 if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
1178 g_debug(
"Look for default config file: %s", etc);
1186 extern const char *rasi_theme_file_extensions[];
1189 GFile *gf = g_file_new_for_path(file2);
1190 char *filename = g_file_get_path(gf);
1193 if (filename && g_file_test(filename, G_FILE_TEST_EXISTS)) {
1207 g_warning(
"Failed to parse theme: \"%s\"",
config.theme);
1222 g_debug(
"Failed to load theme. Try to load default: ");
1225 TICK_N(
"Load cmd config ");
1230 if (
config.cache_dir != NULL) {
1234 if (g_mkdir_with_parents(
cache_dir, 0700) < 0) {
1235 g_warning(
"Failed to create cache directory: %s", g_strerror(errno));
1236 return EXIT_FAILURE;
1240 char *windowid = NULL;
1245 return EXIT_FAILURE;
1251 config.monitor = g_strdup_printf(
"wid:%s", windowid);
1252 windowid =
config.monitor;
1261 for (
int index = 0; theme_str[index]; index++) {
1263 g_warning(
"Failed to parse -theme-str option: \"%s\"",
1273 if (
find_arg(
"-dump-theme") >= 0) {
1276 return EXIT_SUCCESS;
1278 if (
find_arg(
"-dump-processed-theme") >= 0) {
1282 return EXIT_SUCCESS;
1284 if (
find_arg(
"-dump-config") >= 0) {
1287 return EXIT_SUCCESS;
1290 if (
find_arg(
"-list-keybindings") >= 0) {
1291 int is_term = isatty(fileno(stdout));
1293 return EXIT_SUCCESS;
1296 unsigned int interval = 1;
1298 g_timeout_add((guint)(1000 / (
double)interval),
record, NULL);
1303 if (
find_arg(
"-benchmark-ui") >= 0) {
1304 config.benchmark_ui = TRUE;
1313 help(argc, argv, FALSE);
1315 return EXIT_SUCCESS;
1318 help(argc, argv, TRUE);
1320 return EXIT_SUCCESS;
1324#ifdef ENABLE_WAYLAND
1326 g_warning(
"No valid backend was found. Make sure to launch %s from a valid "
1327 "X11 or Wayland session.",
1330 g_warning(
"No valid backend was found. Make sure to launch %s from a valid "
1336 g_warning(
"No valid backend was found. Make sure to launch %s from a valid "
1341 return EXIT_FAILURE;
1345 TICK_N(
"Workers initialize");
1347 TICK_N(
"Icon fetcher initialize");
1349 gboolean kill_running = FALSE;
1351 kill_running = TRUE;
1355 TICK_N(
"Pid file created");
1358 return EXIT_FAILURE;
1361 TICK_N(
"Text box setup");
1364 g_warning(
"Failed to properly finish display setup");
1366 return EXIT_FAILURE;
1368 TICK_N(
"Setup late Display");
1397 return EXIT_SUCCESS;
1401 iter = g_list_next(iter)) {
1402 fputs(((GString *)iter->data)->str, stderr);
1403 fputs(
"\n", stderr);
1406 iter = g_list_next(iter)) {
1407 fputs(((GString *)iter->data)->str, stderr);
1408 fputs(
"\n", stderr);
1411 return EXIT_FAILURE;
1416 if (index != NULL) {
1420 config.completer_mode == NULL ?
"(null)" :
config.completer_mode;
1421 g_warning(
"Mode: %s not found or is not valid for use as completer.", name);
gboolean display_late_setup(void)
void display_early_cleanup(void)
void display_init(const display_proxy *disp_in)
void display_cleanup(void)
guint display_scale(void)
static const display_proxy * proxy
gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings)
void display_dump_monitor_layout(void)
void config_parse_cmd_options(void)
void config_parser_add_option(XrmOptionType type, const char *key, void **value, const char *comment)
void print_help_msg(const char *option, const char *type, const char *text, const char *def, int isatty)
void config_parse_dump_config_rasi_format(FILE *out, gboolean changes)
Dump configuration in rasi format.
void config_xresource_free(void)
Mode recursive_browser_mode
void cmd_set_arguments(int argc, char **argv)
const char ** find_arg_strv(const char *const key)
char * rofi_expand_path(const char *input)
void remove_pid_file(int fd)
int find_arg_str(const char *const key, char **val)
int find_arg_uint(const char *const key, unsigned int *val)
int find_arg(const char *const key)
int create_pid_file(const char *pidfile, gboolean kill_running)
int config_sanity_check(void)
void rofi_icon_fetcher_destroy(void)
void rofi_icon_fetcher_init(void)
gboolean parse_keys_abe(NkBindings *bindings)
void abe_list_all_bindings(gboolean is_term)
void mode_destroy(Mode *mode)
const char * mode_get_name(const Mode *mode)
int mode_init(Mode *mode)
void mode_free(Mode **mode)
int mode_get_abi_version(Mode *const mode)
ModeMode mode_result(Mode *mode, int menu_retv, char **input, unsigned int selected_line)
void mode_plugin_set_module(Mode *mode, GModule *mod)
GModule * mode_plugin_get_module(Mode *mode)
void mode_set_config(Mode *mode)
const Mode * rofi_get_mode(unsigned int index)
void rofi_quit_main_loop(void)
unsigned int rofi_get_num_enabled_modes(void)
void rofi_clear_error_messages(void)
void rofi_clear_warning_messages(void)
void rofi_set_return_code(int code)
const Mode * rofi_get_completer(void)
Mode * rofi_collect_modes_search(const char *name)
int mode_lookup(const char *name)
void rofi_add_error_message(GString *str)
void rofi_add_warning_message(GString *str)
void script_mode_gather_user_scripts(void)
gboolean script_mode_is_valid(const char *token)
void script_user_list(gboolean is_term)
void script_mode_cleanup(void)
Mode * script_mode_parse_setup(const char *str)
void textbox_cleanup(void)
void textbox_cursor_end(textbox *tb)
void textbox_text(textbox *tb, const char *text)
void rofi_view_cleanup(void)
void __create_window(MenuFlags menu_flags)
void rofi_view_clear_input(RofiViewState *state)
void rofi_view_switch_mode(RofiViewState *state, Mode *mode)
void rofi_view_remove_active(RofiViewState *state)
int rofi_view_error_dialog(const char *msg, int markup)
void rofi_view_set_active(RofiViewState *state)
RofiViewState * rofi_view_get_active(void)
MenuReturn rofi_view_get_return_value(const RofiViewState *state)
const char * rofi_view_get_user_input(const RofiViewState *state)
void rofi_view_set_selected_line(RofiViewState *state, unsigned int selected_line)
void rofi_view_free(RofiViewState *state)
RofiViewState * rofi_view_create(Mode *sw, const char *input, MenuFlags menu_flags, void(*finalize)(RofiViewState *))
unsigned int rofi_view_get_selected_line(const RofiViewState *state)
void rofi_capture_screenshot(void)
void rofi_view_workers_initialize(void)
void rofi_view_workers_finalize(void)
char * helper_get_theme_path(const char *file, const char **ext, const char *parent_file)
static void rofi_collect_modes(void)
int main(int argc, char *argv[])
GList * list_of_warning_msgs
GList * list_of_error_msgs
static void help(G_GNUC_UNUSED int argc, char **argv, const gboolean compact)
static gboolean record(G_GNUC_UNUSED void *data)
G_MODULE_EXPORT char * config_path
static void print_main_application_options(int is_term)
static void print_list_of_modes(int is_term)
static void run_mode_index(ModeMode mode)
static void rofi_custom_log_function(const char *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, const gchar *message, gpointer user_data)
gboolean display_setup_success
static void help_print_mode_not_found(const char *mode)
static void cleanup(void)
static gboolean startup(G_GNUC_UNUSED gpointer data)
static void print_backend_info(void)
static gboolean setup_modes(void)
int rofi_theme_rasi_validate(const char *filename)
static void rofi_collectmodes_setup(void)
static void teardown(int pfd)
static gboolean rofi_collectmodes_add(Mode *mode)
static gboolean take_screenshot_quit(G_GNUC_UNUSED void *data)
static void rofi_collectmodes_destroy(void)
void process_result(RofiViewState *state)
#define ROFI_MAX_DMENU_INPUT
static const Mode * mode_available_lookup(const char *name)
static int add_mode(const char *token)
static gboolean main_loop_signal_handler_int(G_GNUC_UNUSED gpointer data)
static void show_error_dialog(void)
int rofi_is_in_dmenu_mode
static void help_print_no_arguments(void)
static void help_print_disabled_mode(const char *mode)
unsigned int num_available_modes
static void rofi_collectmodes_dir(const char *base_dir)
void rofi_theme_free_parsed_files(void)
void rofi_theme_print_parsed_files(gboolean is_term)
void rofi_theme_print(ThemeWidget *wid)
void rofi_theme_parse_process_links(void)
void rofi_theme_parse_process_conditionals(void)
void rofi_theme_free(ThemeWidget *wid)
void rofi_theme_reset(void)
void rofi_theme_set_disp_scale_func(disp_scale_func func)
gboolean rofi_theme_parse_string(const char *string)
gboolean rofi_theme_parse_file(const char *file)
display_proxy *const wayland_proxy
display_proxy *const xcb_proxy
char * x11_helper_get_window_manager(void)
ThemeWidget * rofi_configuration