AboutDialog.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. * AboutDialog.cpp
  3. * ---------------
  4. * Purpose: About dialog with credits, system information and a fancy demo effect.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "resource.h"
  11. #include "AboutDialog.h"
  12. #include "Image.h"
  13. #include "Mptrack.h"
  14. #include "TrackerSettings.h"
  15. #include "BuildVariants.h"
  16. #include "../common/version.h"
  17. #include "../misc/mptWine.h"
  18. OPENMPT_NAMESPACE_BEGIN
  19. CAboutDlg *CAboutDlg::instance = nullptr;
  20. BEGIN_MESSAGE_MAP(CRippleBitmap, CWnd)
  21. ON_WM_PAINT()
  22. ON_WM_ERASEBKGND()
  23. ON_WM_MOUSEMOVE()
  24. ON_WM_MOUSEHOVER()
  25. ON_WM_MOUSELEAVE()
  26. END_MESSAGE_MAP()
  27. CRippleBitmap::CRippleBitmap()
  28. {
  29. m_bitmapSrc = LoadPixelImage(GetResource(MAKEINTRESOURCE(IDB_MPTRACK), _T("PNG")));
  30. m_bitmapTarget = std::make_unique<RawGDIDIB>(m_bitmapSrc->Width(), m_bitmapSrc->Height());
  31. m_offset1.assign(m_bitmapSrc->Pixels().size(), 0);
  32. m_offset2.assign(m_bitmapSrc->Pixels().size(), 0);
  33. m_frontBuf = m_offset2.data();
  34. m_backBuf = m_offset1.data();
  35. // Pre-fill first and last row of output bitmap, since those won't be touched.
  36. const RawGDIDIB::Pixel *in1 = m_bitmapSrc->Pixels().data(), *in2 = m_bitmapSrc->Pixels().data() + (m_bitmapSrc->Height() - 1) * m_bitmapSrc->Width();
  37. RawGDIDIB::Pixel *out1 = m_bitmapTarget->Pixels().data(), *out2 = m_bitmapTarget->Pixels().data() + (m_bitmapSrc->Height() - 1) * m_bitmapSrc->Width();
  38. for(uint32 i = 0; i < m_bitmapSrc->Width(); i++)
  39. {
  40. *(out1++) = *(in1++);
  41. *(out2++) = *(in2++);
  42. }
  43. MemsetZero(m_bi);
  44. m_bi.biSize = sizeof(BITMAPINFOHEADER);
  45. m_bi.biWidth = m_bitmapSrc->Width();
  46. m_bi.biHeight = -(int32)m_bitmapSrc->Height();
  47. m_bi.biPlanes = 1;
  48. m_bi.biBitCount = 32;
  49. m_bi.biCompression = BI_RGB;
  50. m_bi.biSizeImage = m_bitmapSrc->Width() * m_bitmapSrc->Height() * 4;
  51. }
  52. CRippleBitmap::~CRippleBitmap()
  53. {
  54. if(!m_showMouse)
  55. {
  56. ShowCursor(TRUE);
  57. }
  58. }
  59. void CRippleBitmap::OnMouseMove(UINT nFlags, CPoint point)
  60. {
  61. // Rate limit in order to avoid too may ripples.
  62. DWORD now = timeGetTime();
  63. if(now - m_lastRipple < UPDATE_INTERVAL)
  64. return;
  65. m_lastRipple = now;
  66. // Initiate ripples at cursor location
  67. point.x = Util::ScalePixelsInv(point.x, m_hWnd);
  68. point.y = Util::ScalePixelsInv(point.y, m_hWnd);
  69. Limit(point.x, 1, int(m_bitmapSrc->Width()) - 2);
  70. Limit(point.y, 2, int(m_bitmapSrc->Height()) - 3);
  71. int32 *p = m_backBuf + point.x + point.y * m_bitmapSrc->Width();
  72. p[0] += (nFlags & MK_LBUTTON) ? 50 : 150;
  73. p[0] += (nFlags & MK_MBUTTON) ? 150 : 0;
  74. int32 w = m_bitmapSrc->Width();
  75. // Make the initial point of this ripple a bit "fatter".
  76. p[-1] += p[0] / 2; p[1] += p[0] / 2;
  77. p[-w] += p[0] / 2; p[w] += p[0] / 2;
  78. p[-w - 1] += p[0] / 4; p[-w + 1] += p[0] / 4;
  79. p[w - 1] += p[0] / 4; p[w + 1] += p[0] / 4;
  80. m_damp = !(nFlags & MK_RBUTTON);
  81. m_activity = true;
  82. // Wine will only ever generate MouseLeave message when the message
  83. // queue is completely empty and the hover timeout has expired.
  84. // This results in a hidden mouse cursor long after it had already left the
  85. // control.
  86. // Avoid hiding the mouse cursor on Wine. Interferring with the users input
  87. // methods is an absolute no-go.
  88. if(mpt::OS::Windows::IsWine())
  89. {
  90. return;
  91. }
  92. TRACKMOUSEEVENT me;
  93. me.cbSize = sizeof(TRACKMOUSEEVENT);
  94. me.hwndTrack = m_hWnd;
  95. me.dwFlags = TME_LEAVE | TME_HOVER;
  96. me.dwHoverTime = 1500;
  97. if(TrackMouseEvent(&me) && m_showMouse)
  98. {
  99. ShowCursor(FALSE);
  100. m_showMouse = false;
  101. }
  102. }
  103. void CRippleBitmap::OnMouseLeave()
  104. {
  105. if(!m_showMouse)
  106. {
  107. ShowCursor(TRUE);
  108. m_showMouse = true;
  109. }
  110. }
  111. void CRippleBitmap::OnPaint()
  112. {
  113. CPaintDC dc(this);
  114. CRect rect;
  115. GetClientRect(rect);
  116. StretchDIBits(dc.m_hDC,
  117. 0, 0, rect.Width(), rect.Height(),
  118. 0, 0, m_bitmapTarget->Width(), m_bitmapTarget->Height(),
  119. m_bitmapTarget->Pixels().data(),
  120. reinterpret_cast<BITMAPINFO *>(&m_bi), DIB_RGB_COLORS, SRCCOPY);
  121. }
  122. bool CRippleBitmap::Animate()
  123. {
  124. // Were there any pixels being moved in the last frame?
  125. if(!m_activity)
  126. return false;
  127. DWORD now = timeGetTime();
  128. if(now - m_lastFrame < UPDATE_INTERVAL)
  129. return true;
  130. m_lastFrame = now;
  131. m_activity = false;
  132. m_frontBuf = (m_frame ? m_offset2 : m_offset1).data();
  133. m_backBuf = (m_frame ? m_offset1 : m_offset2).data();
  134. // Spread the ripples...
  135. const int32 w = m_bitmapSrc->Width(), h = m_bitmapSrc->Height();
  136. const int32 numPixels = w * (h - 2);
  137. const int32 *back = m_backBuf + w;
  138. int32 *front = m_frontBuf + w;
  139. for(int32 i = numPixels; i != 0; i--, back++, front++)
  140. {
  141. (*front) = (back[-1] + back[1] + back[w] + back[-w]) / 2 - (*front);
  142. if(m_damp) (*front) -= (*front) >> 5;
  143. }
  144. // ...and compute the final picture.
  145. const int32 *offset = m_frontBuf + w;
  146. const RawGDIDIB::Pixel *pixelIn = m_bitmapSrc->Pixels().data() + w;
  147. RawGDIDIB::Pixel *pixelOut = m_bitmapTarget->Pixels().data() + w;
  148. RawGDIDIB::Pixel *limitMin = m_bitmapSrc->Pixels().data(), *limitMax = m_bitmapSrc->Pixels().data() + m_bitmapSrc->Pixels().size() - 1;
  149. for(int32 i = numPixels; i != 0; i--, pixelIn++, pixelOut++, offset++)
  150. {
  151. // Compute pixel displacement
  152. const int32 xOff = offset[-1] - offset[1];
  153. const int32 yOff = offset[-w] - offset[w];
  154. if(xOff | yOff)
  155. {
  156. const RawGDIDIB::Pixel *p = pixelIn + xOff + yOff * w;
  157. Limit(p, limitMin, limitMax);
  158. // Add a bit of shading depending on how far we're displacing the pixel...
  159. pixelOut->r = mpt::saturate_cast<uint8>(p->r + (p->r * xOff) / 32);
  160. pixelOut->g = mpt::saturate_cast<uint8>(p->g + (p->g * xOff) / 32);
  161. pixelOut->b = mpt::saturate_cast<uint8>(p->b + (p->b * xOff) / 32);
  162. // ...and mix it with original picture
  163. pixelOut->r = (pixelOut->r + pixelIn->r) / 2u;
  164. pixelOut->g = (pixelOut->g + pixelIn->g) / 2u;
  165. pixelOut->b = (pixelOut->b + pixelIn->b) / 2u;
  166. // And now some cheap image smoothing...
  167. pixelOut[-1].r = (pixelOut->r + pixelOut[-1].r) / 2u;
  168. pixelOut[-1].g = (pixelOut->g + pixelOut[-1].g) / 2u;
  169. pixelOut[-1].b = (pixelOut->b + pixelOut[-1].b) / 2u;
  170. pixelOut[-w].r = (pixelOut->r + pixelOut[-w].r) / 2u;
  171. pixelOut[-w].g = (pixelOut->g + pixelOut[-w].g) / 2u;
  172. pixelOut[-w].b = (pixelOut->b + pixelOut[-w].b) / 2u;
  173. m_activity = true; // Also use this to update activity status...
  174. } else
  175. {
  176. *pixelOut = *pixelIn;
  177. }
  178. }
  179. m_frame = !m_frame;
  180. InvalidateRect(NULL, FALSE);
  181. return true;
  182. }
  183. CAboutDlg::~CAboutDlg()
  184. {
  185. instance = nullptr;
  186. }
  187. void CAboutDlg::OnOK()
  188. {
  189. instance = nullptr;
  190. if(m_TimerID != 0)
  191. {
  192. KillTimer(m_TimerID);
  193. m_TimerID = 0;
  194. }
  195. DestroyWindow();
  196. delete this;
  197. }
  198. void CAboutDlg::OnCancel()
  199. {
  200. OnOK();
  201. }
  202. BOOL CAboutDlg::OnInitDialog()
  203. {
  204. CDialog::OnInitDialog();
  205. mpt::ustring app;
  206. app += MPT_UFORMAT("OpenMPT{} ({} ({} bit))")(
  207. BuildVariants().GetBuildVariantDescription(BuildVariants().GetBuildVariant()),
  208. mpt::OS::Windows::Name(mpt::OS::Windows::GetProcessArchitecture()),
  209. mpt::arch_bits)
  210. + U_("\n");
  211. app += U_("Version ") + Build::GetVersionStringSimple() + U_("\n\n");
  212. app += Build::GetURL(Build::Url::Website) + U_("\n");
  213. SetDlgItemText(IDC_EDIT3, mpt::ToCString(mpt::String::Replace(app, U_("\n"), U_("\r\n"))));
  214. m_bmp.SubclassDlgItem(IDC_BITMAP1, this);
  215. m_Tab.InsertItem(TCIF_TEXT, 0, _T("OpenMPT"), 0, 0, 0, 0);
  216. m_Tab.InsertItem(TCIF_TEXT, 1, _T("Components"), 0, 0, 0, 0);
  217. m_Tab.InsertItem(TCIF_TEXT, 2, _T("Credits"), 0, 0, 0, 0);
  218. m_Tab.InsertItem(TCIF_TEXT, 3, _T("License"), 0, 0, 0, 0);
  219. m_Tab.InsertItem(TCIF_TEXT, 4, _T("Resources"), 0, 0, 0, 0);
  220. if(mpt::OS::Windows::IsWine()) m_Tab.InsertItem(TCIF_TEXT, 5, _T("Wine"), 0, 0, 0, 0);
  221. m_Tab.SetCurSel(0);
  222. OnTabChange(nullptr, nullptr);
  223. if(m_TimerID != 0)
  224. {
  225. KillTimer(m_TimerID);
  226. m_TimerID = 0;
  227. }
  228. m_TimerID = SetTimer(TIMERID_ABOUT_DEFAULT, CRippleBitmap::UPDATE_INTERVAL, nullptr);
  229. return TRUE;
  230. }
  231. void CAboutDlg::OnTimer(UINT_PTR nIDEvent)
  232. {
  233. if(nIDEvent == m_TimerID)
  234. {
  235. m_bmp.Animate();
  236. }
  237. }
  238. void CAboutDlg::OnTabChange(NMHDR * /*pNMHDR*/ , LRESULT * /*pResult*/ )
  239. {
  240. m_TabEdit.SetWindowText(mpt::ToCString(mpt::String::Replace(GetTabText(m_Tab.GetCurSel()), U_("\n"), U_("\r\n"))));
  241. }
  242. #ifdef MPT_ENABLE_ARCH_INTRINSICS
  243. static mpt::ustring ProcSupportToString(uint32 procSupport)
  244. {
  245. std::vector<mpt::ustring> features;
  246. #if MPT_COMPILER_MSVC
  247. #if defined(MPT_ENABLE_ARCH_X86)
  248. features.push_back(U_("x86"));
  249. #endif
  250. #if defined(MPT_ENABLE_ARCH_AMD64)
  251. features.push_back(U_("amd64"));
  252. #endif
  253. struct ProcFlag
  254. {
  255. decltype(procSupport) flag;
  256. const char *name;
  257. };
  258. static constexpr ProcFlag flags[] =
  259. {
  260. { 0, "" },
  261. #if defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64)
  262. { CPU::feature::mmx, "mmx" },
  263. { CPU::feature::sse, "sse" },
  264. { CPU::feature::sse2, "sse2" },
  265. { CPU::feature::sse3, "sse3" },
  266. { CPU::feature::ssse3, "ssse3" },
  267. { CPU::feature::sse4_1, "sse4.1" },
  268. { CPU::feature::sse4_2, "sse4.2" },
  269. { CPU::feature::avx, "avx" },
  270. { CPU::feature::avx2, "avx2" },
  271. #endif
  272. };
  273. for(const auto &f : flags)
  274. {
  275. if(procSupport & f.flag) features.push_back(mpt::ToUnicode(mpt::Charset::ASCII, f.name));
  276. }
  277. #else
  278. MPT_UNUSED_VARIABLE(procSupport);
  279. #endif
  280. return mpt::String::Combine(features, U_(" "));
  281. }
  282. #endif // MPT_ENABLE_ARCH_INTRINSICS
  283. mpt::ustring CAboutDlg::GetTabText(int tab)
  284. {
  285. const mpt::ustring lf = U_("\n");
  286. const mpt::ustring yes = U_("yes");
  287. const mpt::ustring no = U_("no");
  288. #ifdef MPT_ENABLE_ARCH_INTRINSICS
  289. const CPU::Info CPUInfo = CPU::Info::Get();
  290. #endif // MPT_ENABLE_ARCH_INTRINSICS
  291. mpt::ustring text;
  292. switch(tab)
  293. {
  294. case 0:
  295. text = U_("OpenMPT - Open ModPlug Tracker\n\n")
  296. + MPT_UFORMAT("Version: {}\n")(Build::GetVersionStringExtended())
  297. + MPT_UFORMAT("Source Code: {}\n")(SourceInfo::Current().GetUrlWithRevision() + UL_(" ") + SourceInfo::Current().GetStateString())
  298. + MPT_UFORMAT("Build Date: {}\n")(Build::GetBuildDateString())
  299. + MPT_UFORMAT("Compiler: {}\n")(Build::GetBuildCompilerString())
  300. + MPT_UFORMAT("Architecture: {}\n")(mpt::OS::Windows::Name(mpt::OS::Windows::GetProcessArchitecture()))
  301. + MPT_UFORMAT("Required Windows Kernel Level: {}\n")(mpt::OS::Windows::Version::GetName(mpt::OS::Windows::Version::GetMinimumKernelLevel()))
  302. + MPT_UFORMAT("Required Windows API Level: {}\n")(mpt::OS::Windows::Version::GetName(mpt::OS::Windows::Version::GetMinimumAPILevel()));
  303. {
  304. text += U_("Required CPU features: ");
  305. std::vector<mpt::ustring> features;
  306. #if MPT_COMPILER_MSVC
  307. #if defined(_M_X64)
  308. features.push_back(U_("x86-64"));
  309. if(CPU::GetMinimumFeatures() & CPU::feature::avx) features.push_back(U_("avx"));
  310. if(CPU::GetMinimumFeatures() & CPU::feature::avx2) features.push_back(U_("avx2"));
  311. #elif defined(_M_IX86)
  312. if(CPU::GetMinimumFeatures() & CPU::feature::sse) features.push_back(U_("sse"));
  313. if(CPU::GetMinimumFeatures() & CPU::feature::sse2) features.push_back(U_("sse2"));
  314. if(CPU::GetMinimumFeatures() & CPU::feature::avx) features.push_back(U_("avx"));
  315. if(CPU::GetMinimumFeatures() & CPU::feature::avx2) features.push_back(U_("avx2"));
  316. #else
  317. if(CPU::GetMinimumFeatures() & CPU::feature::sse) features.push_back(U_("sse"));
  318. if(CPU::GetMinimumFeatures() & CPU::feature::sse2) features.push_back(U_("sse2"));
  319. if(CPU::GetMinimumFeatures() & CPU::feature::avx) features.push_back(U_("avx"));
  320. if(CPU::GetMinimumFeatures() & CPU::feature::avx2) features.push_back(U_("avx2"));
  321. #endif
  322. #endif
  323. text += mpt::String::Combine(features, U_(" "));
  324. text += lf;
  325. }
  326. #ifdef MPT_ENABLE_ARCH_INTRINSICS
  327. text += MPT_UFORMAT("Optional CPU features used: {}\n")(ProcSupportToString(CPU::GetEnabledFeatures()));
  328. #endif // MPT_ENABLE_ARCH_INTRINSICS
  329. text += lf;
  330. text += MPT_UFORMAT("System Architecture: {}\n")(mpt::OS::Windows::Name(mpt::OS::Windows::GetHostArchitecture()));
  331. #ifdef MPT_ENABLE_ARCH_INTRINSICS
  332. text += MPT_UFORMAT("CPU: {}, Family {}, Model {}, Stepping {}\n")
  333. ( mpt::ToUnicode(mpt::Charset::ASCII, (std::strlen(CPUInfo.VendorID) > 0) ? std::string(CPUInfo.VendorID) : std::string("Generic"))
  334. , CPUInfo.Family
  335. , CPUInfo.Model
  336. , CPUInfo.Stepping
  337. );
  338. text += MPT_UFORMAT("CPU Name: {}\n")(mpt::ToUnicode(mpt::Charset::ASCII, (std::strlen(CPUInfo.BrandID) > 0) ? std::string(CPUInfo.BrandID) : std::string("")));
  339. text += MPT_UFORMAT("Available CPU features: {}\n")(ProcSupportToString(CPUInfo.AvailableFeatures));
  340. #endif // MPT_ENABLE_ARCH_INTRINSICS
  341. text += MPT_UFORMAT("Operating System: {}\n\n")(mpt::OS::Windows::Version::GetName(mpt::OS::Windows::Version::Current()));
  342. text += MPT_UFORMAT("OpenMPT Install Path{1}: {0}\n")(theApp.GetInstallPath(), theApp.IsPortableMode() ? U_(" (portable)") : U_(""));
  343. text += MPT_UFORMAT("OpenMPT Executable Path{1}: {0}\n")(theApp.GetInstallBinArchPath(), theApp.IsPortableMode() ? U_(" (portable)") : U_(""));
  344. text += MPT_UFORMAT("Settings{1}: {0}\n")(theApp.GetConfigFileName(), theApp.IsPortableMode() ? U_(" (portable)") : U_(""));
  345. break;
  346. case 1:
  347. {
  348. std::vector<std::string> components = ComponentManager::Instance()->GetRegisteredComponents();
  349. if(!TrackerSettings::Instance().ComponentsKeepLoaded)
  350. {
  351. text += U_("Components are loaded and unloaded as needed.\n\n");
  352. for(const auto &component : components)
  353. {
  354. ComponentInfo info = ComponentManager::Instance()->GetComponentInfo(component);
  355. mpt::ustring name = mpt::ToUnicode(mpt::Charset::ASCII, (info.name.substr(0, 9) == "Component") ? info.name.substr(9) : info.name);
  356. if(!info.settingsKey.empty())
  357. {
  358. name = mpt::ToUnicode(mpt::Charset::ASCII, info.settingsKey);
  359. }
  360. text += name + lf;
  361. }
  362. } else
  363. {
  364. for(int available = 1; available >= 0; --available)
  365. {
  366. if(available)
  367. {
  368. text += U_("Loaded Components:\n");
  369. } else
  370. {
  371. text += U_("\nUnloaded Components:\n");
  372. }
  373. for(const auto &component : components)
  374. {
  375. ComponentInfo info = ComponentManager::Instance()->GetComponentInfo(component);
  376. if(available && info.state != ComponentStateAvailable) continue;
  377. if(!available && info.state == ComponentStateAvailable) continue;
  378. mpt::ustring name = mpt::ToUnicode(mpt::Charset::ASCII, (info.name.substr(0, 9) == "Component") ? info.name.substr(9) : info.name);
  379. if(!info.settingsKey.empty())
  380. {
  381. name = mpt::ToUnicode(mpt::Charset::ASCII, info.settingsKey);
  382. }
  383. text += MPT_UFORMAT("{}: {}")
  384. ( name
  385. , info.state == ComponentStateAvailable ? U_("ok") :
  386. info.state == ComponentStateUnavailable? U_("missing") :
  387. info.state == ComponentStateUnintialized ? U_("not loaded") :
  388. info.state == ComponentStateBlocked ? U_("blocked") :
  389. info.state == ComponentStateUnregistered ? U_("unregistered") :
  390. U_("unknown")
  391. );
  392. if(info.type != ComponentTypeUnknown)
  393. {
  394. text += MPT_UFORMAT(" ({})")
  395. ( info.type == ComponentTypeBuiltin ? U_("builtin") :
  396. info.type == ComponentTypeSystem ? U_("system") :
  397. info.type == ComponentTypeSystemInstallable ? U_("system, optional") :
  398. info.type == ComponentTypeBundled ? U_("bundled") :
  399. info.type == ComponentTypeForeign ? U_("foreign") :
  400. U_("unknown")
  401. );
  402. }
  403. text += lf;
  404. }
  405. }
  406. }
  407. }
  408. break;
  409. case 2:
  410. text += Build::GetFullCreditsString();
  411. break;
  412. case 3:
  413. text += Build::GetLicenseString();
  414. break;
  415. case 4:
  416. text += U_("Website:\n") + Build::GetURL(Build::Url::Website);
  417. text += U_("\n\nForum:\n") + Build::GetURL(Build::Url::Forum);
  418. text += U_("\n\nBug Tracker:\n") + Build::GetURL(Build::Url::Bugtracker);
  419. text += U_("\n\nUpdates:\n") + Build::GetURL(Build::Url::Updates);
  420. break;
  421. case 5:
  422. try
  423. {
  424. if(!theApp.GetWine())
  425. {
  426. text += U_("Wine integration not available.\n");
  427. } else
  428. {
  429. mpt::Wine::Context & wine = *theApp.GetWine();
  430. text += MPT_UFORMAT("Windows: {}\n")
  431. ( mpt::OS::Windows::Version::Current().IsWindows() ? yes : no
  432. );
  433. text += MPT_UFORMAT("Windows version: {}\n")
  434. (
  435. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::Win81) ? U_("Windows 8.1") :
  436. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::Win8) ? U_("Windows 8") :
  437. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::Win7) ? U_("Windows 7") :
  438. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::WinVista) ? U_("Windows Vista") :
  439. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::WinXP) ? U_("Windows XP") :
  440. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::Win2000) ? U_("Windows 2000") :
  441. mpt::OS::Windows::Version::Current().IsAtLeast(mpt::OS::Windows::Version::WinNT4) ? U_("Windows NT4") :
  442. U_("unknown")
  443. );
  444. text += MPT_UFORMAT("Windows original: {}\n")
  445. ( mpt::OS::Windows::IsOriginal() ? yes : no
  446. );
  447. text += U_("\n");
  448. text += MPT_UFORMAT("Wine: {}\n")
  449. ( mpt::OS::Windows::IsWine() ? yes : no
  450. );
  451. text += MPT_UFORMAT("Wine Version: {}\n")
  452. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.VersionContext().RawVersion())
  453. );
  454. text += MPT_UFORMAT("Wine Build ID: {}\n")
  455. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.VersionContext().RawBuildID())
  456. );
  457. text += MPT_UFORMAT("Wine Host Sys Name: {}\n")
  458. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.VersionContext().RawHostSysName())
  459. );
  460. text += MPT_UFORMAT("Wine Host Release: {}\n")
  461. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.VersionContext().RawHostRelease())
  462. );
  463. text += U_("\n");
  464. text += MPT_UFORMAT("uname -m: {}\n")
  465. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.Uname_m())
  466. );
  467. text += MPT_UFORMAT("HOME: {}\n")
  468. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.HOME())
  469. );
  470. text += MPT_UFORMAT("XDG_DATA_HOME: {}\n")
  471. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.XDG_DATA_HOME())
  472. );
  473. text += MPT_UFORMAT("XDG_CACHE_HOME: {}\n")
  474. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.XDG_CACHE_HOME())
  475. );
  476. text += MPT_UFORMAT("XDG_CONFIG_HOME: {}\n")
  477. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.XDG_CONFIG_HOME())
  478. );
  479. text += U_("\n");
  480. text += MPT_UFORMAT("OpenMPT folder: {}\n")
  481. ( theApp.GetInstallPath().ToUnicode()
  482. );
  483. text += MPT_UFORMAT("OpenMPT folder (host): {}\n")
  484. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.PathToPosix(theApp.GetInstallPath()))
  485. );
  486. text += MPT_UFORMAT("OpenMPT config folder: {}\n")
  487. ( theApp.GetConfigPath().ToUnicode()
  488. );
  489. text += MPT_UFORMAT("OpenMPT config folder (host): {}\n")
  490. ( mpt::ToUnicode(mpt::Charset::UTF8, wine.PathToPosix(theApp.GetConfigPath()))
  491. );
  492. text += MPT_UFORMAT("Host root: {}\n")
  493. ( wine.PathToWindows("/").ToUnicode()
  494. );
  495. }
  496. } catch(const mpt::Wine::Exception & e)
  497. {
  498. text += U_("Exception: ") + mpt::get_exception_text<mpt::ustring>(e) + U_("\n");
  499. }
  500. break;
  501. }
  502. return text;
  503. }
  504. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  505. {
  506. CDialog::DoDataExchange(pDX);
  507. DDX_Control(pDX, IDC_TABABOUT, m_Tab);
  508. DDX_Control(pDX, IDC_EDITABOUT, m_TabEdit);
  509. }
  510. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  511. ON_WM_TIMER()
  512. ON_NOTIFY(TCN_SELCHANGE, IDC_TABABOUT, &CAboutDlg::OnTabChange)
  513. END_MESSAGE_MAP()
  514. OPENMPT_NAMESPACE_END