Github每日精选(第8期):rofi窗口切换器

rofi

Rofi最初是由Sean Pringle编写的 simpleswitcher 的克隆——一个大致基于superswitcher的弹出窗口切换器。Simpleswitcher 奠定了基础,因此 Sean Pringle 的这个工具值得称赞。Rofi (重命名,因为它失去了简单的属性)已经扩展了额外的功能,比如应用程序启动器和 ssh-launcher,并且可以作为 dmenu 替代品,使其成为一个非常通用的工具。

Rofi和 dmenu 一样,将为用户提供一个文本选项列表,其中可以选择一个或多个选项。这可以是运行应用程序、选择窗口或外部脚本提供的选项。

在这里插入图片描述
rofi在github下的地址在这里

模式

Rofi有几种实现常见用例的内置模式,并且可以通过脚本(从 Rofi调用或调用Rofi)或插件进行扩展。

以下是不同模式的列表:

  • run:从 $PATH 启动应用程序,可选择在终端中启动。
  • drun:基于桌面文件启动应用程序。它试图符合 XDG 标准。
  • window:在兼容 EWMH 的窗口管理器上的窗口之间切换。
  • ssh:通过 ssh 连接到远程主机。
  • 文件浏览器:用于打开文件的基本文件浏览器。
  • keys:列出内部键绑定。
  • script:使用简单脚本编写(有限)自定义模式。
  • combi:将多种模式合二为一。

众所周知, Rofi可以在 Linux 和 BSD 上工作。

rofi在ubuntu下的使用

从源中直接安装如下:

apt install rofi

非常方便,这样我们就完成了rofi的安装,运行rofi

rofi -show run

在这里插入图片描述
生成默认配置文件

mkdir -p ~/.config/rofi
rofi -dump-config > ~/.config/rofi/config.rasi

这将创建一个在文件夹中调用config.rasi~/.config/rofi/文件。您可以修改此文件以设置配置设置和修改主题。config.rasirofi 默认查找的文件。

有关配置选项的摘要,请参阅配置指南。手册页中提供了更详细的选项。

主代码

rofi使用的是c语言进行编写,主程序在main.c文件中:

int main(int argc, char *argv[]) {
  cmd_set_arguments(argc, argv);
  if (find_arg("-log") >= 0) {
    char *logfile = NULL;
    find_arg_str("-log", &logfile);
    if (logfile != NULL) {
      int fp = open(logfile, O_CLOEXEC | O_APPEND | O_CREAT | O_WRONLY,
                    S_IRUSR | S_IWUSR);
      if (fp != -1) {
        g_log_set_default_handler(rofi_custom_log_function,
                                  GINT_TO_POINTER(fp));

      } else {
        g_error("Failed to open logfile '%s': %s.", logfile, strerror(errno));
      }

    } else {
      g_warning("Option '-log' should pass in a filename.");
    }
  }
  TIMINGS_START();

  // Version
  if (find_arg("-v") >= 0 || find_arg("-version") >= 0) {
#ifdef GIT_VERSION
    g_print("Version: " GIT_VERSION "\n");
#else
    g_print("Version: " VERSION "\n");
#endif
    return EXIT_SUCCESS;
  }

  if (find_arg("-rasi-validate") >= 0) {
    char *str = NULL;
    find_arg_str("-rasi-validate", &str);
    if (str != NULL) {
      int retv = rofi_theme_rasi_validate(str);
      cleanup();
      return retv;
    }
    fprintf(stderr, "Usage: %s -rasi-validate my-theme.rasi", argv[0]);
    return EXIT_FAILURE;
  }

  {
    const char *ro_pid = g_getenv("ROFI_OUTSIDE");
    if (ro_pid != NULL) {
      pid_t ro_pidi = (pid_t)g_ascii_strtoll(ro_pid, NULL, 0);
      if (kill(ro_pidi, 0) == 0) {
        printf("Do not launch rofi from inside rofi.\r\n");
        return EXIT_FAILURE;
      }
    }
  }

  // Detect if we are in dmenu mode.
  // This has two possible causes.
  // 1 the user specifies it on the command-line.
  if (find_arg("-dmenu") >= 0) {
    dmenu_mode = TRUE;
  }
  // 2 the binary that executed is called dmenu (e.g. symlink to rofi)
  else {
    // Get the base name of the executable called.
    char *base_name = g_path_get_basename(argv[0]);
    const char *const dmenu_str = "dmenu";
    dmenu_mode = (strcmp(base_name, dmenu_str) == 0);
    // Free the basename for dmenu detection.
    g_free(base_name);
  }
  TICK();

  // Create pid file path.
  const char *path = g_get_user_runtime_dir();
  if (path) {
    if (g_mkdir_with_parents(path, 0700) < 0) {
      g_warning("Failed to create user runtime directory: %s with error: %s",
                path, g_strerror(errno));
      pidfile = g_build_filename(g_get_home_dir(), ".rofi.pid", NULL);
    } else {
      pidfile = g_build_filename(path, "rofi.pid", NULL);
    }
  }
  config_parser_add_option(xrm_String, "pid", (void **)&pidfile,
                           "Pidfile location");

  /** default configuration */
  if (find_arg("-no-default-config") < 0) {
    GBytes *theme_data = g_resource_lookup_data(
        resources_get_resource(), "/org/qtools/rofi/default_configuration.rasi",
        G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
    if (theme_data) {
      const char *theme = g_bytes_get_data(theme_data, NULL);
      if (rofi_theme_parse_string((const char *)theme)) {
        g_warning("Failed to parse default configuration. Giving up..");
        if (list_of_error_msgs) {
          for (GList *iter = g_list_first(list_of_error_msgs); iter != NULL;
               iter = g_list_next(iter)) {
            g_warning("Error: %s%s%s", color_bold, ((GString *)iter->data)->str,
                      color_reset);
          }
        }
        rofi_configuration = NULL;
        cleanup();
        return EXIT_FAILURE;
      }
      g_bytes_unref(theme_data);
    }
  }

  if (find_arg("-config") < 0) {
    const char *cpath = g_get_user_config_dir();
    if (cpath) {
      config_path = g_build_filename(cpath, "rofi", "config.rasi", NULL);
    }
  } else {
    char *c = NULL;
    find_arg_str("-config", &c);
    config_path = rofi_expand_path(c);
  }

  TICK();
  if (setlocale(LC_ALL, "") == NULL) {
    g_warning("Failed to set locale.");
    cleanup();
    return EXIT_FAILURE;
  }

  TICK_N("Setup Locale");
  rofi_collect_modes();
  TICK_N("Collect MODES");
  rofi_collectmodes_setup();
  TICK_N("Setup MODES");

  main_loop = g_main_loop_new(NULL, FALSE);

  TICK_N("Setup mainloop");

  bindings = nk_bindings_new(0lu);
  TICK_N("NK Bindings");

  if (!display_setup(main_loop, bindings)) {
    g_warning("Connection has error");
    cleanup();
    return EXIT_FAILURE;
  }
  TICK_N("Setup Display");

  // Setup keybinding
  setup_abe();
  TICK_N("Setup abe");

  if (find_arg("-no-config") < 0) {
    // Load distro default settings
    gboolean found_system = FALSE;
    const char *const *dirs = g_get_system_config_dirs();
    if (dirs) {
      for (unsigned int i = 0; !found_system && dirs[i]; i++) {
        /** New format. */
        gchar *etc = g_build_filename(dirs[i], "rofi.rasi", NULL);
        g_debug("Look for default config file: %s", etc);
        if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
          g_debug("Parsing: %s", etc);
          rofi_theme_parse_file(etc);
          found_system = TRUE;
        }
        g_free(etc);
      }
    }
    if (!found_system) {
      /** New format. */
      gchar *etc = g_build_filename(SYSCONFDIR, "rofi.rasi", NULL);
      g_debug("Look for default config file: %s", etc);
      if (g_file_test(etc, G_FILE_TEST_IS_REGULAR)) {
        g_debug("Look for default config file: %s", etc);
        rofi_theme_parse_file(etc);
      }
      g_free(etc);
    }

    if (config_path && g_file_test(config_path, G_FILE_TEST_IS_REGULAR)) {
      if (rofi_theme_parse_file(config_path)) {
        rofi_theme_free(rofi_theme);
        rofi_theme = NULL;
      }
    }
  }
  find_arg_str("-theme", &(config.theme));
  if (config.theme) {
    TICK_N("Parse theme");
    rofi_theme_reset();
    if (rofi_theme_parse_file(config.theme)) {
      g_warning("Failed to parse theme: \"%s\"", config.theme);
      // TODO: instantiate fallback theme.?
      rofi_theme_free(rofi_theme);
      rofi_theme = NULL;
    }
    TICK_N("Parsed theme");
  }
  // Parse command line for settings, independent of other -no-config.
  if (list_of_error_msgs == NULL) {
    // Only call this when there are no errors.
    // This might clear existing errors.
    config_parse_cmd_options();
  }
  TICK_N("Load cmd config ");

  // Get the path to the cache dir.
  cache_dir = g_get_user_cache_dir();

  if (config.cache_dir != NULL) {
    cache_dir = config.cache_dir;
  }

  if (g_mkdir_with_parents(cache_dir, 0700) < 0) {
    g_warning("Failed to create cache directory: %s", g_strerror(errno));
    return EXIT_FAILURE;
  }

  /** dirty hack for dmenu compatibility */
  char *windowid = NULL;
  if (!dmenu_mode) {
    // setup_modes
    if (setup_modes()) {
      cleanup();
      return EXIT_FAILURE;
    }
    TICK_N("Setup Modes");
  } else {
    // Hack for dmenu compatibility.
    if (find_arg_str("-w", &windowid) == TRUE) {
      config.monitor = g_strdup_printf("wid:%s", windowid);
      windowid = config.monitor;
    }
  }

  /**
   * Make small commandline changes to the current theme.
   */
  const char **theme_str = find_arg_strv("-theme-str");
  if (theme_str) {
    for (int index = 0; theme_str && theme_str[index]; index++) {
      if (rofi_theme_parse_string(theme_str[index])) {
        g_warning("Failed to parse -theme-str option: \"%s\"",
                  theme_str[index]);
        rofi_theme_free(rofi_theme);
        rofi_theme = NULL;
      }
    }
    g_free(theme_str);
  }

  parse_keys_abe(bindings);
  if (find_arg("-dump-theme") >= 0) {
    rofi_theme_print(rofi_theme);
    cleanup();
    return EXIT_SUCCESS;
  }
  if (find_arg("-dump-processed-theme") >= 0) {
    rofi_theme_parse_process_conditionals();
    rofi_theme_print(rofi_theme);
    cleanup();
    return EXIT_SUCCESS;
  }
  if (find_arg("-dump-config") >= 0) {
    config_parse_dump_config_rasi_format(stdout, FALSE);
    cleanup();
    return EXIT_SUCCESS;
  }
  // Dump.
  // catch help request
  if (find_arg("-h") >= 0 || find_arg("-help") >= 0 ||
      find_arg("--help") >= 0) {
    help(argc, argv);
    cleanup();
    return EXIT_SUCCESS;
  }

  unsigned int interval = 1;
  if (find_arg_uint("-record-screenshots", &interval)) {
    g_timeout_add((guint)(1000 / (double)interval), record, NULL);
  }
  if (find_arg("-benchmark-ui") >= 0) {
    config.benchmark_ui = TRUE;
  }

  rofi_view_workers_initialize();
  TICK_N("Workers initialize");
  rofi_icon_fetcher_init();
  TICK_N("Icon fetcher initialize");

  gboolean kill_running = FALSE;
  if (find_arg("-replace") >= 0) {
    kill_running = TRUE;
  }
  // Create pid file
  int pfd = create_pid_file(pidfile, kill_running);
  TICK_N("Pid file created");
  if (pfd < 0) {
    cleanup();
    return EXIT_FAILURE;
  }
  textbox_setup();
  TICK_N("Text box setup");

  if (!display_late_setup()) {
    g_warning("Failed to properly finish display setup");
    cleanup();
    return EXIT_FAILURE;
  }
  TICK_N("Setup late Display");

  rofi_theme_parse_process_conditionals();
  rofi_theme_parse_process_links();
  TICK_N("Theme setup");

  // Setup signal handling sources.
  // SIGINT
  g_unix_signal_add(SIGINT, main_loop_signal_handler_int, NULL);

  g_idle_add(startup, NULL);

  // Start mainloop.
  g_main_loop_run(main_loop);
  teardown(pfd);
  cleanup();

  /* dirty hack */
  g_free(windowid);
  return return_code;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go2coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值