AppFile.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright (c) 2020, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Function.h>
  8. #include <AK/Vector.h>
  9. #include <LibCore/ConfigFile.h>
  10. #include <LibCore/DirIterator.h>
  11. #include <LibDesktop/AppFile.h>
  12. #include <errno.h>
  13. #include <serenity.h>
  14. #include <spawn.h>
  15. namespace Desktop {
  16. NonnullRefPtr<AppFile> AppFile::get_for_app(const StringView& app_name)
  17. {
  18. auto path = String::formatted("{}/{}.af", APP_FILES_DIRECTORY, app_name);
  19. return open(path);
  20. }
  21. NonnullRefPtr<AppFile> AppFile::open(const StringView& path)
  22. {
  23. return adopt_ref(*new AppFile(path));
  24. }
  25. void AppFile::for_each(Function<void(NonnullRefPtr<AppFile>)> callback, const StringView& directory)
  26. {
  27. Core::DirIterator di(directory, Core::DirIterator::SkipDots);
  28. if (di.has_error())
  29. return;
  30. while (di.has_next()) {
  31. auto name = di.next_path();
  32. if (!name.ends_with(".af"))
  33. continue;
  34. auto path = String::formatted("{}/{}", directory, name);
  35. auto af = AppFile::open(path);
  36. if (!af->is_valid())
  37. continue;
  38. callback(af);
  39. }
  40. }
  41. AppFile::AppFile(const StringView& path)
  42. : m_config(Core::ConfigFile::open(path))
  43. , m_valid(validate())
  44. {
  45. }
  46. AppFile::~AppFile()
  47. {
  48. }
  49. bool AppFile::validate() const
  50. {
  51. if (m_config->read_entry("App", "Name").trim_whitespace().is_empty())
  52. return false;
  53. if (m_config->read_entry("App", "Executable").trim_whitespace().is_empty())
  54. return false;
  55. return true;
  56. }
  57. String AppFile::name() const
  58. {
  59. auto name = m_config->read_entry("App", "Name").trim_whitespace();
  60. VERIFY(!name.is_empty());
  61. return name;
  62. }
  63. String AppFile::executable() const
  64. {
  65. auto executable = m_config->read_entry("App", "Executable").trim_whitespace();
  66. VERIFY(!executable.is_empty());
  67. return executable;
  68. }
  69. String AppFile::description() const
  70. {
  71. return m_config->read_entry("App", "Description").trim_whitespace();
  72. }
  73. String AppFile::category() const
  74. {
  75. return m_config->read_entry("App", "Category").trim_whitespace();
  76. }
  77. String AppFile::icon_path() const
  78. {
  79. return m_config->read_entry("App", "IconPath").trim_whitespace();
  80. }
  81. GUI::Icon AppFile::icon() const
  82. {
  83. auto override_icon = icon_path();
  84. // FIXME: support pointing to actual .ico files
  85. if (!override_icon.is_empty())
  86. return GUI::FileIconProvider::icon_for_path(override_icon);
  87. return GUI::FileIconProvider::icon_for_path(executable());
  88. }
  89. bool AppFile::run_in_terminal() const
  90. {
  91. return m_config->read_bool_entry("App", "RunInTerminal", false);
  92. }
  93. Vector<String> AppFile::launcher_file_types() const
  94. {
  95. Vector<String> file_types;
  96. for (auto& entry : m_config->read_entry("Launcher", "FileTypes").split(',')) {
  97. entry = entry.trim_whitespace();
  98. if (!entry.is_empty())
  99. file_types.append(entry);
  100. }
  101. return file_types;
  102. }
  103. Vector<String> AppFile::launcher_protocols() const
  104. {
  105. Vector<String> protocols;
  106. for (auto& entry : m_config->read_entry("Launcher", "Protocols").split(',')) {
  107. entry = entry.trim_whitespace();
  108. if (!entry.is_empty())
  109. protocols.append(entry);
  110. }
  111. return protocols;
  112. }
  113. bool AppFile::spawn() const
  114. {
  115. if (!is_valid())
  116. return false;
  117. pid_t child_pid;
  118. const char* argv[] = { executable().characters(), nullptr };
  119. if ((errno = posix_spawn(&child_pid, executable().characters(), nullptr, nullptr, const_cast<char**>(argv), environ))) {
  120. perror("posix_spawn");
  121. return false;
  122. } else if (disown(child_pid) < 0) {
  123. perror("disown");
  124. return false;
  125. }
  126. return true;
  127. }
  128. }