The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
build_info.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2015 - 2025
3 by Iris Morelle <shadowm2006@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-lib"
17
18#include "build_info.hpp"
19
20#include "desktop/version.hpp"
21#include "filesystem.hpp"
22#include "formatter.hpp"
23#include "gettext.hpp"
26#include "game_version.hpp"
27#include "sound.hpp"
28#include "video.hpp"
29#include "addon/manager.hpp"
30#include "sdl/point.hpp"
31#include "utils/charconv.hpp"
32
33#include <algorithm>
34#include <fstream>
35#include <iomanip>
36
37#include "lua/wrapper_lua.h"
38
39#include <SDL3_image/SDL_image.h>
40#include <SDL3_mixer/SDL_mixer.h>
41
42#include <boost/algorithm/string.hpp>
43#include <boost/predef.h>
44#include <boost/version.hpp>
45
46#if defined(__APPLE__)
47#include <TargetConditionals.h>
48#endif
49
50#ifndef __APPLE__
51#include <openssl/crypto.h>
52#include <openssl/opensslv.h>
53#endif
54
55#if !(defined(__APPLE__) && TARGET_OS_IPHONE)
56#include <curl/curl.h>
57#endif
58
59#include <pango/pangocairo.h>
60
61#ifdef __APPLE__
62// apple_notification.mm uses Foundation.h, which is an Objective-C header;
63// but CoreFoundation.h is a C header which also defines these.
64#include <CoreFoundation/CoreFoundation.h>
65#endif
66
67namespace game_config
68{
69
70namespace {
71
72struct version_table_manager
73{
74 std::vector<std::string> compiled, linked, names;
75 std::vector<optional_feature> features;
76
77 version_table_manager();
78};
79
80const version_table_manager versions;
81
82std::string format_version(unsigned a, unsigned b, unsigned c)
83{
84 return formatter() << a << '.' << b << '.' << c;
85}
86
87#ifndef __APPLE__
88
89std::string format_openssl_patch_level(uint8_t p)
90{
91 return p <= 26
92 ? std::string(1, 'a' + static_cast<char>(p) - 1)
93 : "patch" + std::to_string(p);
94}
95
96std::string format_openssl_version(long v)
97{
98 int major, minor, fix, patch, status;
99 std::ostringstream fmt;
100
101 //
102 // The people who maintain OpenSSL are not from this world. I suppose it's
103 // only fair that I'm the one who gets to try to make sense of their version
104 // encoding scheme. -- shadowm
105 //
106
107 if(v < 0x0930L) {
108 // Pre-0.9.3 seems simpler times overall.
109 minor = v & 0x0F00L >> 8;
110 fix = v & 0x00F0L >> 4;
111 patch = v & 0x000FL;
112
113 fmt << "0." << minor << '.' << fix;
114 if(patch) {
115 fmt << format_openssl_patch_level(patch);
116 }
117 } else {
118 //
119 // Note that they either assume the major version will never be greater than
120 // 9, they plan to use hexadecimal digits for versions 10.x.x through
121 // 15.x.x, or they expect long to be always > 32-bits by then. Who the hell
122 // knows, really.
123 //
124 major = (v & 0xF0000000L) >> 28;
125 minor = (v & 0x0FF00000L) >> 20;
126 fix = (v & 0x000FF000L) >> 12;
127 patch = (v & 0x00000FF0L) >> 4;
128 status = (v & 0x0000000FL);
129
130 if(v < 0x00905100L) {
131 //
132 // From wiki.openssl.org (also mentioned in opensslv.h, in the most oblique
133 // fashion possible):
134 //
135 // "Versions between 0.9.3 and 0.9.5 had a version identifier with this interpretation:
136 // MMNNFFRBB major minor fix final beta/patch"
137 //
138 // Both the wiki and opensslv.h fail to accurately list actual version
139 // numbers that ended up used in the wild -- e.g. 0.9.3a is supposedly
140 // 0x0090301f when it really was 0x00903101.
141 //
142 const uint8_t is_final = (v & 0xF00L) >> 8;
143 status = is_final ? 0xF : 0;
144 patch = v & 0xFFL;
145 } else if(v < 0x00906000L) {
146 //
147 // Quoth opensslv.h:
148 //
149 // "For continuity reasons (because 0.9.5 is already out, and is coded
150 // 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
151 // part is slightly different, by setting the highest bit. This means
152 // that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start
153 // with 0x0090600S..."
154 //
155 patch ^= 1 << 7;
156 }
157
158 fmt << major << '.' << minor << '.' << fix;
159
160 if(patch) {
161 fmt << format_openssl_patch_level(patch);
162 }
163
164 if(status == 0x0) {
165 fmt << "-dev";
166 } else if(status < 0xF) {
167 fmt << "-beta" << status;
168 }
169 }
170
171 return fmt.str();
172}
173
174#endif
175
176version_table_manager::version_table_manager()
177 : compiled(LIB_COUNT, "")
178 , linked(LIB_COUNT, "")
179 , names(LIB_COUNT, "")
180 , features()
181{
182 //
183 // SDL
184 //
185
186 compiled[LIB_SDL] = format_version(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION);
187 int linked_sdl_version = SDL_GetVersion();
188 linked[LIB_SDL] = format_version(SDL_VERSIONNUM_MAJOR(linked_sdl_version), SDL_VERSIONNUM_MINOR(linked_sdl_version), SDL_VERSIONNUM_MICRO(linked_sdl_version));
189
190 names[LIB_SDL] = "SDL";
191
192 //
193 // SDL_image
194 //
195
196 compiled[LIB_SDL_IMAGE] = format_version(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_MICRO_VERSION);
197
198 int linked_img_version = IMG_Version();
199 linked[LIB_SDL_IMAGE] = format_version(SDL_VERSIONNUM_MAJOR(linked_img_version), SDL_VERSIONNUM_MINOR(linked_img_version), SDL_VERSIONNUM_MICRO(linked_img_version));
200
201 names[LIB_SDL_IMAGE] = "SDL_image";
202
203 //
204 // SDL_mixer
205 //
206
207 compiled[LIB_SDL_MIXER] = format_version(SDL_MIXER_MAJOR_VERSION, SDL_MIXER_MINOR_VERSION, SDL_MIXER_MICRO_VERSION);
208
209 int linked_mix_version = MIX_Version();
210 linked[LIB_SDL_MIXER] = format_version(SDL_VERSIONNUM_MAJOR(linked_mix_version), SDL_VERSIONNUM_MINOR(linked_mix_version), SDL_VERSIONNUM_MICRO(linked_mix_version));
211
212 names[LIB_SDL_MIXER] = "SDL_mixer";
213
214 //
215 // Boost
216 //
217
218 compiled[LIB_BOOST] = BOOST_LIB_VERSION;
219 std::replace(compiled[LIB_BOOST].begin(), compiled[LIB_BOOST].end(), '_', '.');
220 names[LIB_BOOST] = "Boost";
221
222 //
223 // Lua
224 //
225
226 compiled[LIB_LUA] = LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "." LUA_VERSION_RELEASE;
227 names[LIB_LUA] = "Lua";
228
229 //
230 // OpenSSL/libcrypto
231 //
232
233#ifndef __APPLE__
234 compiled[LIB_CRYPTO] = format_openssl_version(OPENSSL_VERSION_NUMBER);
235 linked[LIB_CRYPTO] = format_openssl_version(SSLeay());
236 names[LIB_CRYPTO] = "OpenSSL/libcrypto";
237#endif
238
239 //
240 // libcurl
241 //
242
243#if defined(__APPLE__) && TARGET_OS_IPHONE
244 compiled[LIB_CURL] = "unavailable";
245 linked[LIB_CURL] = "unavailable";
246 names[LIB_CURL] = "libcurl";
247#else
248 compiled[LIB_CURL] = format_version(
249 (LIBCURL_VERSION_NUM & 0xFF0000) >> 16,
250 (LIBCURL_VERSION_NUM & 0x00FF00) >> 8,
251 LIBCURL_VERSION_NUM & 0x0000FF);
252 curl_version_info_data *curl_ver = curl_version_info(CURLVERSION_NOW);
253 if(curl_ver && curl_ver->version) {
254 linked[LIB_CURL] = curl_ver->version;
255 }
256 // This is likely to upset somebody out there, but the cURL authors
257 // consistently call it 'libcurl' (all lowercase) in all documentation.
258 names[LIB_CURL] = "libcurl";
259#endif
260
261 //
262 // Cairo
263 //
264
265 compiled[LIB_CAIRO] = CAIRO_VERSION_STRING;
266 linked[LIB_CAIRO] = cairo_version_string();
267 names[LIB_CAIRO] = "Cairo";
268
269 //
270 // Pango
271 //
272
273 compiled[LIB_PANGO] = PANGO_VERSION_STRING;
274 linked[LIB_PANGO] = pango_version_string();
275 names[LIB_PANGO] = "Pango";
276
277 //
278 // Features table.
279 //
280
281 features.emplace_back(N_("feature^Lua console completion"));
282#ifdef HAVE_HISTORY
283 features.back().enabled = true;
284#endif
285
286#ifdef _X11
287
288 features.emplace_back(N_("feature^D-Bus notifications back end"));
289#ifdef HAVE_LIBDBUS
290 features.back().enabled = true;
291#endif
292
293#endif /* _X11 */
294
295#ifdef _WIN32
296 // Always compiled in.
297 features.emplace_back(N_("feature^Win32 notifications back end"));
298 features.back().enabled = true;
299#endif
300
301#ifdef __APPLE__
302 // Always compiled in.
303 features.emplace_back(N_("feature^Cocoa notifications back end"));
304 features.back().enabled = true;
305#endif /* __APPLE__ */
306}
307
308const std::string empty_version = "";
309
310} // end anonymous namespace 1
311
312std::string build_arch()
313{
314#if BOOST_ARCH_X86_64
315 return "x86_64";
316#elif BOOST_ARCH_X86_32
317 return "x86";
318#elif BOOST_ARCH_ARM && (defined(__arm64) || defined(_M_ARM64))
319 return "arm64";
320#elif BOOST_ARCH_ARM
321 return "arm";
322#elif BOOST_ARCH_IA64
323 return "ia64";
324#elif BOOST_ARCH_PPC
325 return "ppc";
326#elif BOOST_ARCH_ALPHA
327 return "alpha";
328#elif BOOST_ARCH_MIPS
329 return "mips";
330#elif BOOST_ARCH_SPARC
331 return "sparc";
332#else
333 #warning Unrecognized platform or Boost.Predef broken/unavailable
334 // Congratulations, you're running Wesnoth on an exotic platform -- either that or you live in
335 // the foretold future where x86 and ARM stopped being the dominant CPU architectures for the
336 // general-purpose consumer market. If you want to add label support for your platform, check
337 // out the Boost.Predef library's documentation and alter the code above accordingly.
338 //
339 // On the other hand, if you got here looking for Wesnoth's biggest secret let me just say
340 // right here and now that Irdya is round. There, I said the thing that nobody has dared say
341 // in mainline content before.
342 return _("cpu_architecture^<unknown>");
343#endif
344}
345
346std::vector<optional_feature> optional_features_table(bool localize)
347{
348 std::vector<optional_feature> res = versions.features;
349
350 for(std::size_t k = 0; k < res.size(); ++k) {
351 if(localize) {
352 res[k].name = _(res[k].name.c_str());
353 } else {
354 // Strip annotation carets ("blah blah^actual text here") from translatable
355 // strings.
356 const auto caret_pos = res[k].name.find('^');
357 if(caret_pos != std::string::npos) {
358 res[k].name.erase(0, caret_pos + 1);
359 }
360 }
361 }
362 return res;
363}
364
365const std::string& library_build_version(LIBRARY_ID lib)
366{
367 if(lib >= LIB_COUNT) {
368 return empty_version;
369 }
370
371 return versions.compiled[lib];
372}
373
374const std::string& library_runtime_version(LIBRARY_ID lib)
375{
376 if(lib >= LIB_COUNT) {
377 return empty_version;
378 }
379
380 return versions.linked[lib];
381}
382
383const std::string& library_name(LIBRARY_ID lib)
384{
385 if(lib >= LIB_COUNT) {
386 return empty_version;
387 }
388
389 return versions.names[lib];
390}
391
392std::string dist_channel_id()
393{
394 std::string info;
395 std::ifstream infofile(game_config::path + "/data/dist");
396 if(infofile.is_open()) {
397 std::getline(infofile, info);
398 infofile.close();
399 boost::trim(info);
400 }
401
402 if(info.empty()) {
403 return "Default";
404 }
405
406 return info;
407}
408
409namespace {
410
411/**
412 * Formats items into a tidy 2-column list with a fixed-length first column.
413 */
414class list_formatter
415{
416public:
417 using list_entry = std::pair<std::string, std::string>;
418 using contents_list = std::vector<list_entry>;
419
420 list_formatter(const std::string& heading, const contents_list& contents = {}, const std::string& empty_placeholder = "")
421 : heading_(heading)
422 , placeholder_(empty_placeholder)
423 , contents_(contents)
424 {
425 }
426
427 void insert(const std::string& label, const std::string& value)
428 {
429 contents_.emplace_back(label, value);
430 }
431
432 void set_placeholder(const std::string& placeholder)
433 {
434 placeholder_ = placeholder;
435 }
436
437 void stream_put(std::ostream& os) const;
438
439private:
440 static const char heading_delimiter;
441 static const std::string label_delimiter;
442
443 std::string heading_;
444 std::string placeholder_;
445
446 contents_list contents_;
447};
448
449const char list_formatter::heading_delimiter = '=';
450const std::string list_formatter::label_delimiter = ": ";
451
452void list_formatter::stream_put(std::ostream& os) const
453{
454 if(!heading_.empty()) {
455 os << heading_ << '\n' << std::string(utf8::size(heading_), heading_delimiter) << "\n\n";
456 }
457
458 if(contents_.empty() && !placeholder_.empty()) {
459 os << placeholder_ << '\n';
460 } else if(!contents_.empty()) {
461 auto label_length_comparator = [](const list_entry& a, const list_entry& b)
462 {
463 return utf8::size(a.first) < utf8::size(b.first);
464 };
465
466 const auto longest_entry_label = std::max_element(contents_.begin(), contents_.end(), label_length_comparator);
467 const std::size_t min_length = longest_entry_label != contents_.end()
468 ? utf8::size(label_delimiter) + utf8::size(longest_entry_label->first)
469 : 0;
470
471 // Save stream attributes for resetting them later after completing the loop
472 const std::size_t prev_width = os.width();
473 const std::ostream::fmtflags prev_flags = os.flags();
474
475 os << std::left;
476
477 for(const auto& entry : contents_) {
478 os << std::setw(min_length) << entry.first + label_delimiter << entry.second << '\n';
479 }
480
481 os.width(prev_width);
482 os.flags(prev_flags);
483 }
484
485 os << '\n';
486}
487
488std::ostream& operator<<(std::ostream& os, const list_formatter& fmt)
489{
490 fmt.stream_put(os);
491 return os;
492}
493
494list_formatter library_versions_report_internal(const std::string& heading = "")
495{
496 list_formatter fmt{heading};
497
498 for(unsigned n = 0; n < LIB_COUNT; ++n)
499 {
500 if(versions.names[n].empty()) {
501 continue;
502 }
503
504 std::string text = versions.compiled[n];
505 if(!versions.linked[n].empty()) {
506 text += " (runtime " + versions.linked[n] + ")";
507 }
508
509 fmt.insert(versions.names[n], text);
510 }
511
512 return fmt;
513}
514
515list_formatter optional_features_report_internal(const std::string& heading = "")
516{
517 list_formatter fmt{heading};
518
519 const std::vector<optional_feature>& features = optional_features_table(false);
520
521 for(const auto& feature : features) {
522 fmt.insert(feature.name, feature.enabled ? "yes" : "no");
523 }
524
525 return fmt;
526}
527
528inline std::string geometry_to_string(point p)
529{
530 return std::to_string(p.x) + 'x' + std::to_string(p.y);
531}
532
533template<typename coordinateType>
534inline std::string geometry_to_string(coordinateType horizontal, coordinateType vertical)
535{
536 // Use a stream in order to control significant digits in non-integers
537 return formatter() << std::fixed << std::setprecision(2) << horizontal << 'x' << vertical;
538}
539
540std::string format_sdl_driver_list(std::vector<std::string> drivers, const std::string& current_driver)
541{
542 bool found_current_driver = false;
543
544 for(auto& drvname : drivers) {
545 if(current_driver == drvname) {
546 found_current_driver = true;
547 drvname = "[" + current_driver + "]";
548 }
549 }
550
551 if(drivers.empty() || !found_current_driver) {
552 // This shouldn't happen but SDL is weird at times so whatevs
553 drivers.emplace_back("[" + current_driver + "]");
554 }
555
556 return utils::join(drivers, " ");
557}
558
559list_formatter video_settings_report_internal(const std::string& heading = "")
560{
561 list_formatter fmt{heading};
562
563 std::string placeholder;
564
565 if(video::headless()) {
566 placeholder = "Running in non-interactive mode.";
567 }
568
569 if(!video::has_window()) {
570 placeholder = "Video not initialized yet.";
571 }
572
573 if(!placeholder.empty()) {
574 fmt.set_placeholder(placeholder);
575 return fmt;
576 }
577
579 auto drivers = video::enumerate_drivers();
580
581 fmt.insert("SDL video drivers", format_sdl_driver_list(drivers, current_driver));
582 fmt.insert("Window size", geometry_to_string(video::current_resolution()));
583 fmt.insert("Game canvas size", geometry_to_string(video::game_canvas_size()));
584 fmt.insert("Final render target size", geometry_to_string(video::output_size()));
585 fmt.insert("Render refresh rate", std::to_string(video::current_refresh_rate()));
586 fmt.insert("Screen refresh rate", std::to_string(video::native_refresh_rate()));
587 fmt.insert("Content scaling", utils::charconv_buffer(video::content_scaling()).to_string());
588 fmt.insert("Pixel density", utils::charconv_buffer(video::pixel_density()).to_string());
589 fmt.insert("Calculated display scaling", utils::charconv_buffer(video::display_scaling()).to_string());
590 fmt.insert("Available renderers", utils::join(video::get_available_renderers(), " "));
592
593 for(const auto& info : renderer_report) {
594 fmt.insert(info.first, info.second);
595 }
596
597 return fmt;
598}
599
600list_formatter sound_settings_report_internal(const std::string& heading = "")
601{
602 list_formatter fmt{heading};
603
604 const auto& driver_status = sound::driver_status::query();
605
606 if(!driver_status.initialized) {
607 fmt.set_placeholder("Audio not initialized.");
608 return fmt;
609 }
610
612 auto drivers = sound::enumerate_drivers();
613
614 static std::map<uint16_t, std::string> audio_format_names = {
615 // 8 bits
616 { SDL_AUDIO_U8, "unsigned 8 bit" },
617 { SDL_AUDIO_S8, "signed 8 bit" },
618 // 16 bits
619 { SDL_AUDIO_S16LE, "signed 16 bit little-endian" },
620 { SDL_AUDIO_S16BE, "signed 16 bit big-endian" },
621 // 32 bits
622 { SDL_AUDIO_S32LE, "signed 32 bit little-endian" },
623 { SDL_AUDIO_S32BE, "signed 32 bit big-endian" },
624 { SDL_AUDIO_F32LE, "signed 32 bit floating point little-endian" },
625 { SDL_AUDIO_F32BE, "signed 32 bit floating point big-endian" },
626 };
627
628 auto fmt_names_it = audio_format_names.find(driver_status.format);
629 // If we don't recognize the format id just print the raw number
630 const std::string fmt_name = fmt_names_it != audio_format_names.end()
631 ? fmt_names_it->second
632 : formatter() << "0x" << std::setfill('0') << std::setw(2*sizeof(driver_status.format)) << std::hex << std::uppercase << driver_status.format;
633
634 fmt.insert("SDL audio drivers", format_sdl_driver_list(drivers, current_driver));
635 fmt.insert("Number of channels", std::to_string(driver_status.channels));
636 fmt.insert("Output rate", std::to_string(driver_status.frequency) + " Hz");
637 fmt.insert("Sample format", fmt_name);
638
639 return fmt;
640}
641
642} // end anonymous namespace 2
643
645{
646 return formatter{} << library_versions_report_internal();
647}
648
650{
651 return formatter{} << optional_features_report_internal();
652}
653
654std::string full_build_report()
655{
656 list_formatter::contents_list paths{
657 {"Data dir", game_config::path},
658 {"User data dir", filesystem::get_user_data_dir()},
659 {"Saves dir", filesystem::get_saves_dir()},
660 {"Add-ons dir", filesystem::get_addons_dir()},
661 {"Cache dir", filesystem::get_cache_dir()},
662 {"Logs dir", filesystem::get_logs_dir()},
663 };
664
665 // Obfuscate usernames in paths
666 for(auto& entry : paths) {
667 entry.second = filesystem::sanitize_path(entry.second);
668 }
669
670 list_formatter::contents_list addons;
671
672 for(const auto& addon_info : installed_addons_and_versions()) {
673 addons.emplace_back(addon_info.first, addon_info.second);
674 }
675
676 std::ostringstream o;
677
678 o << "The Battle for Wesnoth version " << game_config::revision << " " << build_arch() << '\n'
679 << "Running on " << desktop::os_version() << '\n'
680 << "Distribution channel: " << dist_channel_id() << '\n'
681 << '\n'
682 << list_formatter{"Game paths", paths}
683 << library_versions_report_internal("Libraries")
684 << optional_features_report_internal("Features")
685 << video_settings_report_internal("Current video settings")
686 << sound_settings_report_internal("Current audio settings")
687 << list_formatter("Installed add-ons", addons, "No add-ons installed.");
688
689 return o.str();
690}
691
692} // end namespace game_config
std::ostream & operator<<(std::ostream &s, const ai::attack_result &r)
Definition actions.cpp:1118
std::map< std::string, std::string > installed_addons_and_versions()
Retrieves the ids and versions of all installed add-ons.
Definition manager.cpp:191
static const char heading_delimiter
std::vector< optional_feature > features
std::string heading_
std::vector< std::string > compiled
std::string placeholder_
contents_list contents_
std::vector< std::string > linked
std::vector< std::string > names
static const std::string label_delimiter
std::ostringstream wrapper.
Definition formatter.hpp:40
Platform identification and version information functions.
Declarations for File-IO.
Interfaces for manipulating version numbers of engine, add-ons, etc.
#define N_(String)
Definition gettext.hpp:108
static std::string _(const char *str)
Definition gettext.hpp:100
std::string label
What to show in the filter's drop-down list.
Definition manager.cpp:201
std::string os_version()
Returns a string with the running OS name and version information.
Definition version.cpp:220
std::string get_cache_dir()
std::string get_user_data_dir()
std::string get_saves_dir()
std::string get_logs_dir()
std::string get_addons_dir()
std::string sanitize_path(const std::string &path)
Sanitizes a path to remove references to the user's name.
Game configuration data as global variables.
const std::string & library_name(LIBRARY_ID lib)
Retrieve the user-visible name for the given library.
std::string path
std::string full_build_report()
Produce a bug report-style info dump.
std::string library_versions_report()
Produce a plain-text report of library versions suitable for stdout/stderr.
std::vector< optional_feature > optional_features_table(bool localize)
Retrieve the features table.
const std::string & library_runtime_version(LIBRARY_ID lib)
Retrieve the runtime version number of the given library.
const std::string & library_build_version(LIBRARY_ID lib)
Retrieve the build-time version number of the given library.
std::string build_arch()
Obtain the processor architecture for this build.
std::string optional_features_report()
Produce a plain-text report of features suitable for stdout/stderr.
const std::string revision
std::string dist_channel_id()
Return the distribution channel identifier, or "Default" if missing.
logger & info()
Definition log.cpp:351
std::vector< std::string > enumerate_drivers()
Definition sound.cpp:414
std::string current_driver()
Definition sound.cpp:408
STL namespace.
T end(const std::pair< T, T > &p)
T begin(const std::pair< T, T > &p)
std::string & insert(std::string &str, const std::size_t pos, const std::string &insert)
Insert a UTF-8 string at the specified position.
Definition unicode.cpp:100
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition unicode.cpp:81
std::string join(const Range &v, const std::string &s=",")
Generates a new string joining container items in a list.
float pixel_density()
Definition video.cpp:513
bool headless()
The game is running headless.
Definition video.cpp:146
std::vector< std::pair< std::string, std::string > > renderer_report()
Provides diagnostic information about the current renderer for the build_info API.
Definition video.cpp:906
float content_scaling()
Definition video.cpp:505
point output_size()
Returns the size of the final render target.
Definition video.cpp:410
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition video.cpp:432
bool has_window()
Whether the game has set up a window to render into.
Definition video.cpp:405
std::vector< std::string > enumerate_drivers()
A list of available video drivers.
Definition video.cpp:727
std::vector< std::string > get_available_renderers()
Returns a list of all available renderers.
Definition video.cpp:894
point current_resolution()
The current window size in desktop coordinates.
Definition video.cpp:819
int native_refresh_rate()
The native refresh rate of display, not taking any user preferences into account.
Definition video.cpp:490
int current_refresh_rate()
The refresh rate of the screen.
Definition video.cpp:495
std::string current_driver()
The current video driver in use, or else "<not initialized>".
Definition video.cpp:721
float display_scaling()
Definition video.cpp:517
std::string to_string(const Range &range, const Func &op)
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
Holds a 2D point.
Definition point.hpp:25
static driver_status query()
Definition sound.cpp:427
mock_party p
static map_location::direction n
#define c
#define b