AppFile.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * Copyright (c) 2020, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Spencer Dixon <spencercdixon@gmail.com>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/Function.h>
  9. #include <AK/Vector.h>
  10. #include <LibCore/ConfigFile.h>
  11. #include <LibCore/DirIterator.h>
  12. #include <LibCore/Process.h>
  13. #include <LibDesktop/AppFile.h>
  14. #include <LibFileSystem/FileSystem.h>
  15. namespace Desktop {
  16. ByteString AppFile::app_file_path_for_app(StringView app_name)
  17. {
  18. return ByteString::formatted("{}/{}.af", APP_FILES_DIRECTORY, app_name);
  19. }
  20. bool AppFile::exists_for_app(StringView app_name)
  21. {
  22. return FileSystem::exists(app_file_path_for_app(app_name));
  23. }
  24. NonnullRefPtr<AppFile> AppFile::get_for_app(StringView app_name)
  25. {
  26. return open(app_file_path_for_app(app_name));
  27. }
  28. NonnullRefPtr<AppFile> AppFile::open(StringView path)
  29. {
  30. return adopt_ref(*new AppFile(path));
  31. }
  32. void AppFile::for_each(Function<void(NonnullRefPtr<AppFile>)> callback, StringView directory)
  33. {
  34. Core::DirIterator di(directory, Core::DirIterator::SkipDots);
  35. if (di.has_error())
  36. return;
  37. while (di.has_next()) {
  38. auto name = di.next_path();
  39. if (!name.ends_with(".af"sv))
  40. continue;
  41. auto path = ByteString::formatted("{}/{}", directory, name);
  42. auto af = AppFile::open(path);
  43. if (!af->is_valid())
  44. continue;
  45. callback(af);
  46. }
  47. }
  48. AppFile::AppFile(StringView path)
  49. : m_config(Core::ConfigFile::open(path).release_value_but_fixme_should_propagate_errors())
  50. , m_valid(validate())
  51. {
  52. }
  53. bool AppFile::validate() const
  54. {
  55. if (m_config->read_entry("App", "Name").trim_whitespace().is_empty())
  56. return false;
  57. if (m_config->read_entry("App", "Executable").trim_whitespace().is_empty())
  58. return false;
  59. return true;
  60. }
  61. ByteString AppFile::name() const
  62. {
  63. auto name = m_config->read_entry("App", "Name").trim_whitespace().replace("&"sv, ""sv);
  64. VERIFY(!name.is_empty());
  65. return name;
  66. }
  67. ByteString AppFile::menu_name() const
  68. {
  69. auto name = m_config->read_entry("App", "Name").trim_whitespace();
  70. VERIFY(!name.is_empty());
  71. return name;
  72. }
  73. ByteString AppFile::executable() const
  74. {
  75. auto executable = m_config->read_entry("App", "Executable").trim_whitespace();
  76. VERIFY(!executable.is_empty());
  77. return executable;
  78. }
  79. ByteString AppFile::description() const
  80. {
  81. return m_config->read_entry("App", "Description").trim_whitespace();
  82. }
  83. ByteString AppFile::category() const
  84. {
  85. return m_config->read_entry("App", "Category").trim_whitespace();
  86. }
  87. ByteString AppFile::working_directory() const
  88. {
  89. return m_config->read_entry("App", "WorkingDirectory").trim_whitespace();
  90. }
  91. ByteString AppFile::icon_path() const
  92. {
  93. return m_config->read_entry("App", "IconPath").trim_whitespace();
  94. }
  95. GUI::Icon AppFile::icon() const
  96. {
  97. auto override_icon = icon_path();
  98. // FIXME: support pointing to actual .ico files
  99. if (!override_icon.is_empty())
  100. return GUI::FileIconProvider::icon_for_path(override_icon);
  101. return GUI::FileIconProvider::icon_for_path(executable());
  102. }
  103. bool AppFile::run_in_terminal() const
  104. {
  105. return m_config->read_bool_entry("App", "RunInTerminal", false);
  106. }
  107. bool AppFile::requires_root() const
  108. {
  109. return m_config->read_bool_entry("App", "RequiresRoot", false);
  110. }
  111. bool AppFile::exclude_from_system_menu() const
  112. {
  113. return m_config->read_bool_entry("App", "ExcludeFromSystemMenu", false);
  114. }
  115. Vector<ByteString> AppFile::launcher_mime_types() const
  116. {
  117. Vector<ByteString> mime_types;
  118. for (auto& entry : m_config->read_entry("Launcher", "MimeTypes").split(',')) {
  119. entry = entry.trim_whitespace();
  120. if (!entry.is_empty())
  121. mime_types.append(entry);
  122. }
  123. return mime_types;
  124. }
  125. Vector<ByteString> AppFile::launcher_file_types() const
  126. {
  127. Vector<ByteString> file_types;
  128. for (auto& entry : m_config->read_entry("Launcher", "FileTypes").split(',')) {
  129. entry = entry.trim_whitespace();
  130. if (!entry.is_empty())
  131. file_types.append(entry);
  132. }
  133. return file_types;
  134. }
  135. Vector<ByteString> AppFile::launcher_protocols() const
  136. {
  137. Vector<ByteString> protocols;
  138. for (auto& entry : m_config->read_entry("Launcher", "Protocols").split(',')) {
  139. entry = entry.trim_whitespace();
  140. if (!entry.is_empty())
  141. protocols.append(entry);
  142. }
  143. return protocols;
  144. }
  145. bool AppFile::spawn(ReadonlySpan<StringView> arguments) const
  146. {
  147. if (!is_valid())
  148. return false;
  149. auto pid = Core::Process::spawn(executable(), arguments, working_directory());
  150. if (pid.is_error())
  151. return false;
  152. return true;
  153. }
  154. }