CApplicationContext.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "CApplicationContext.h"
  2. #include "Steam/FileSystem/FileSystem.h"
  3. #include "WallpaperEngine/Logging/CLog.h"
  4. #include <cstring>
  5. #include <getopt.h>
  6. #define WORKSHOP_APP_ID 431960
  7. #define APP_DIRECTORY "wallpaper_engine"
  8. using namespace WallpaperEngine::Application;
  9. struct option long_options[] = {
  10. { "screen-root", required_argument, nullptr, 'r' },
  11. { "bg", required_argument, nullptr, 'b' },
  12. { "window", required_argument, nullptr, 'w' },
  13. { "pkg", required_argument, nullptr, 'p' },
  14. { "dir", required_argument, nullptr, 'd' },
  15. { "silent", no_argument, nullptr, 's' },
  16. { "volume", required_argument, nullptr, 'v' },
  17. { "help", no_argument, nullptr, 'h' },
  18. { "fps", required_argument, nullptr, 'f' },
  19. { "assets-dir", required_argument, nullptr, 'a' },
  20. { "screenshot", required_argument, nullptr, 'c' },
  21. { "list-properties", no_argument, nullptr, 'l' },
  22. { "set-property", required_argument, nullptr, 'o' },
  23. { "noautomute", no_argument, nullptr, 'm' },
  24. { "no-fullscreen-pause", no_argument, nullptr, 'n' },
  25. { "disable-mouse", no_argument, nullptr, 'e' },
  26. { nullptr, 0, nullptr, 0 }
  27. };
  28. std::string stringPathFixes (const std::string& s)
  29. {
  30. if (s.empty ())
  31. return s;
  32. std::string str (s);
  33. // remove single-quotes from the arguments
  34. if (str[0] == '\'' && str[str.size () - 1] == '\'')
  35. str
  36. .erase (str.size () - 1, 1)
  37. .erase (0, 1);
  38. return std::move (str);
  39. }
  40. CApplicationContext::CApplicationContext (int argc, char* argv[])
  41. {
  42. // setup structs with sane default values for now
  43. this->settings =
  44. {
  45. .general =
  46. {
  47. .onlyListProperties = false,
  48. .assets = "",
  49. .defaultBackground = "",
  50. .screenBackgrounds = {},
  51. .properties = {},
  52. },
  53. .render =
  54. {
  55. .mode = NORMAL_WINDOW,
  56. .maximumFPS = 30,
  57. .pauseOnFullscreen = true,
  58. .window = { .geometry = {}},
  59. },
  60. .audio =
  61. {
  62. .enabled = true,
  63. .volume = 15,
  64. .automute = true
  65. },
  66. .mouse =
  67. {
  68. .enabled = true,
  69. },
  70. .screenshot =
  71. {
  72. .take = false,
  73. .path = "",
  74. .format = FIF_UNKNOWN,
  75. },
  76. };
  77. int c;
  78. std::string lastScreen;
  79. while ((c = getopt_long (argc, argv, "b:r:p:d:shf:a:w:mn", long_options, nullptr)) != -1)
  80. {
  81. switch (c)
  82. {
  83. case 'n':
  84. this->settings.render.pauseOnFullscreen = false;
  85. break;
  86. case 'b':
  87. if (lastScreen.empty ())
  88. sLog.exception ("--bg has to go after a --screen-root argument");
  89. // no need to check for previous screen being in the list, as it's the only way for this variable
  90. // to have any value
  91. this->settings.general.screenBackgrounds[lastScreen] = translateBackground (optarg);
  92. break;
  93. case 'o':
  94. {
  95. std::string value = optarg;
  96. std::string::size_type equals = value.find ('=');
  97. // properties without value are treated as booleans for now
  98. if (equals == std::string::npos)
  99. this->settings.general.properties[value] = "1";
  100. else
  101. this->settings.general.properties[value.substr (0, equals)] = value.substr (equals + 1);
  102. }
  103. break;
  104. case 'l':
  105. this->settings.general.onlyListProperties = true;
  106. break;
  107. case 'r':
  108. if (this->settings.general.screenBackgrounds.find (optarg) != this->settings.general.screenBackgrounds.end ())
  109. sLog.exception ("Cannot specify the same screen more than once: ", optarg);
  110. if (this->settings.render.mode == EXPLICIT_WINDOW)
  111. sLog.exception ("Cannot run in both background and window mode");
  112. this->settings.render.mode = DESKTOP_BACKGROUND;
  113. lastScreen = optarg;
  114. this->settings.general.screenBackgrounds[lastScreen] = "";
  115. break;
  116. case 'w':
  117. if (this->settings.render.mode == DESKTOP_BACKGROUND)
  118. sLog.exception ("Cannot run in both background and window mode");
  119. if (optarg != nullptr)
  120. {
  121. this->settings.render.mode = EXPLICIT_WINDOW;
  122. // read window geometry
  123. char* pos = optarg;
  124. if (pos != nullptr)
  125. this->settings.render.window.geometry.x = atoi (pos);
  126. if ((pos = strchr (pos, 'x')) != nullptr)
  127. this->settings.render.window.geometry.y = atoi (pos + 1);
  128. if ((pos = strchr (pos + 1, 'x')) != nullptr)
  129. this->settings.render.window.geometry.z = atoi (pos + 1);
  130. if ((pos = strchr (pos + 1, 'x')) != nullptr)
  131. this->settings.render.window.geometry.w = atoi (pos + 1);
  132. }
  133. break;
  134. case 'p':
  135. case 'd':
  136. sLog.error ("--dir/--pkg is deprecated and not used anymore");
  137. this->settings.general.defaultBackground = translateBackground (stringPathFixes (optarg));
  138. break;
  139. case 's':
  140. this->settings.audio.enabled = false;
  141. break;
  142. case 'h':
  143. printHelp (argv[0]);
  144. break;
  145. case 'f':
  146. this->settings.render.maximumFPS = atoi (optarg);
  147. break;
  148. case 'a':
  149. this->settings.general.assets = stringPathFixes (optarg);
  150. break;
  151. case 'v':
  152. this->settings.audio.volume = std::max (atoi (optarg), 128);
  153. break;
  154. case 'c':
  155. this->settings.screenshot.take = true;
  156. this->settings.screenshot.path = stringPathFixes (optarg);
  157. break;
  158. case 'm':
  159. this->settings.audio.automute = false;
  160. break;
  161. case 'e':
  162. this->settings.mouse.enabled = false;
  163. break;
  164. default:
  165. sLog.out ("Default on path parsing: ", optarg);
  166. break;
  167. }
  168. }
  169. if (this->settings.general.defaultBackground.empty ())
  170. {
  171. if (optind < argc && strlen (argv[optind]) > 0)
  172. {
  173. this->settings.general.defaultBackground = translateBackground (argv[optind]);
  174. }
  175. else
  176. {
  177. printHelp (argv[0]);
  178. }
  179. }
  180. // perform some extra validation on the inputs
  181. this->validateAssets ();
  182. this->validateScreenshot ();
  183. // setup application state
  184. this->state.general.keepRunning = true;
  185. this->state.audio.enabled = this->settings.audio.enabled;
  186. this->state.audio.volume = this->settings.audio.volume;
  187. }
  188. std::filesystem::path CApplicationContext::translateBackground (const std::string& bgIdOrPath)
  189. {
  190. if (bgIdOrPath.find ('/') == std::string::npos)
  191. return Steam::FileSystem::workshopDirectory (WORKSHOP_APP_ID, bgIdOrPath);
  192. return bgIdOrPath;
  193. }
  194. void CApplicationContext::validateAssets ()
  195. {
  196. if (!this->settings.general.assets.empty ())
  197. {
  198. sLog.out ("Using wallpaper engine's assets at ", this->settings.general.assets, " based on --assets-dir parameter");
  199. return;
  200. }
  201. try
  202. {
  203. this->settings.general.assets = Steam::FileSystem::appDirectory (APP_DIRECTORY, "assets");
  204. }
  205. catch (std::runtime_error&)
  206. {
  207. // set current path as assets' folder
  208. std::filesystem::path directory = std::filesystem::canonical ("/proc/self/exe").parent_path () / "assets";
  209. }
  210. }
  211. void CApplicationContext::validateScreenshot ()
  212. {
  213. if (!this->settings.screenshot.take)
  214. return;
  215. if (!this->settings.screenshot.path.has_extension ())
  216. sLog.exception ("Cannot determine screenshot format");
  217. std::string extension = this->settings.screenshot.path.extension ();
  218. if (extension == ".bmp")
  219. this->settings.screenshot.format = FIF_BMP;
  220. else if (extension == ".png")
  221. this->settings.screenshot.format = FIF_PNG;
  222. else if (extension == ".jpg" || extension == ".jpeg")
  223. this->settings.screenshot.format = FIF_JPEG;
  224. else
  225. sLog.exception ("Cannot determine screenshot format, unknown extension ", extension);
  226. }
  227. void CApplicationContext::printHelp (const char* route)
  228. {
  229. sLog.out ("Usage: ", route, " [options] background_path/background_id");
  230. sLog.out ("");
  231. sLog.out ("where background_path/background_id can be:");
  232. sLog.out ("\tthe ID of the background (for autodetection on your steam installation)");
  233. sLog.out ("\ta full path to the background's folder");
  234. sLog.out ("");
  235. sLog.out ("options:");
  236. sLog.out ("\t--silent\t\t\t\t\tMutes all the sound the wallpaper might produce");
  237. sLog.out ("\t--volume <amount>\t\t\tSets the volume for all the sounds in the background");
  238. sLog.out ("\t--noautomute\t\t\t\tDisables the automute when an app is playing sound");
  239. sLog.out ("\t--screen-root <screen name>\tDisplay as screen's background");
  240. sLog.out ("\t--window <geometry>\tRuns in window mode, geometry has to be XxYxWxH and sets the position and size of the window");
  241. sLog.out ("\t--fps <maximum-fps>\t\t\tLimits the FPS to the given number, useful to keep battery consumption low");
  242. sLog.out ("\t--assets-dir <path>\t\t\tFolder where the assets are stored");
  243. sLog.out ("\t--screenshot\t\t\t\tTakes a screenshot of the background");
  244. sLog.out ("\t--list-properties\t\t\tList all the available properties and their possible values");
  245. sLog.out ("\t--set-property <name=value>\tOverrides the default value of the given property");
  246. sLog.out ("\t--no-fullscreen-pause\tPrevents the background pausing when an app is fullscreen");
  247. sLog.out ("\t--disable-mouse\tDisables mouse interactions");
  248. }