[XConfig] Implementation of XConfig
This commit is contained in:
committed by
Radosław Gliński
parent
f88bfbe41e
commit
99ea6da18a
426
src/xenia/app/console_settings_dialog.cc
Normal file
426
src/xenia/app/console_settings_dialog.cc
Normal file
@@ -0,0 +1,426 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2026 Xenia Canary. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
#include "xenia/app/emulator_window.h"
|
||||
#include "xenia/app/profile_dialogs.h"
|
||||
#include "xenia/base/png_utils.h"
|
||||
#include "xenia/base/system.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xam/xam_ui.h"
|
||||
#include "xenia/ui/file_picker.h"
|
||||
|
||||
#include "xenia/app/console_settings_dialog.h"
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
|
||||
namespace xe {
|
||||
namespace app {
|
||||
|
||||
static const std::map<uint32_t, std::string> kLanguageMap = {
|
||||
{1, "English"}, {2, "Japanese"},
|
||||
{3, "German"}, {4, "French"},
|
||||
{5, "Spanish"}, {6, "Italian"},
|
||||
{7, "Korean"}, {8, "Traditional Chinese"},
|
||||
{9, "Portuguese"}, {10, "Simplified Chinese"},
|
||||
{11, "Polish"}, {12, "Russian"}};
|
||||
|
||||
static const std::map<uint8_t, std::string> kCountryMap = {
|
||||
{1, "AE"}, {2, "AL"}, {3, "AM"}, {4, "AR"}, {5, "AT"},
|
||||
{6, "AU"}, {7, "AZ"}, {8, "BE"}, {9, "BG"}, {10, "BH"},
|
||||
{11, "BN"}, {12, "BO"}, {13, "BR"}, {14, "BY"}, {15, "BZ"},
|
||||
{16, "CA"}, {18, "CH"}, {19, "CL"}, {20, "CN"}, {21, "CO"},
|
||||
{22, "CR"}, {23, "CZ"}, {24, "DE"}, {25, "DK"}, {26, "DO"},
|
||||
{27, "DZ"}, {28, "EC"}, {29, "EE"}, {30, "EG"}, {31, "ES"},
|
||||
{32, "FI"}, {33, "FO"}, {34, "FR"}, {35, "GB"}, {36, "GE"},
|
||||
{37, "GR"}, {38, "GT"}, {39, "HK"}, {40, "HN"}, {41, "HR"},
|
||||
{42, "HU"}, {43, "ID"}, {44, "IE"}, {45, "IL"}, {46, "IN"},
|
||||
{47, "IQ"}, {48, "IR"}, {49, "IS"}, {50, "IT"}, {51, "JM"},
|
||||
{52, "JO"}, {53, "JP"}, {54, "KE"}, {55, "KG"}, {56, "KR"},
|
||||
{57, "KW"}, {58, "KZ"}, {59, "LB"}, {60, "LI"}, {61, "LT"},
|
||||
{62, "LU"}, {63, "LV"}, {64, "LY"}, {65, "MA"}, {66, "MC"},
|
||||
{67, "MK"}, {68, "MN"}, {69, "MO"}, {70, "MV"}, {71, "MX"},
|
||||
{72, "MY"}, {73, "NI"}, {74, "NL"}, {75, "NO"}, {76, "NZ"},
|
||||
{77, "OM"}, {78, "PA"}, {79, "PE"}, {80, "PH"}, {81, "PK"},
|
||||
{82, "PL"}, {83, "PR"}, {84, "PT"}, {85, "PY"}, {86, "QA"},
|
||||
{87, "RO"}, {88, "RU"}, {89, "SA"}, {90, "SE"}, {91, "SG"},
|
||||
{92, "SI"}, {93, "SK"}, {95, "SV"}, {96, "SY"}, {97, "TH"},
|
||||
{98, "TN"}, {99, "TR"}, {100, "TT"}, {101, "TW"}, {102, "UA"},
|
||||
{103, "US"}, {104, "UY"}, {105, "UZ"}, {106, "VE"}, {107, "VN"},
|
||||
{108, "YE"}, {109, "ZA"},
|
||||
};
|
||||
|
||||
static const std::map<uint32_t, std::string> kAVRegion = {
|
||||
{0x00400100, "NTSC"},
|
||||
{0x00400200, "NTSC-J"},
|
||||
{0x00400400, "PAL"},
|
||||
{0x00800300, "PAL 50Hz"}};
|
||||
|
||||
template <typename T>
|
||||
void DrawCombobox(ImGuiIO& io, std::string_view combobox_name,
|
||||
const std::map<T, std::string>& options, xe::be<T>& value) {
|
||||
const char* preview = "Unknown";
|
||||
for (const auto& opt : options) {
|
||||
if (opt.first == value.get()) {
|
||||
preview = opt.second.data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo(combobox_name.data(), preview)) {
|
||||
for (const auto& opt : options) {
|
||||
const bool selected = (opt.first == value.get());
|
||||
if (ImGui::Selectable(opt.second.data(), selected)) {
|
||||
value = opt.first;
|
||||
}
|
||||
if (selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawResolutionCombobox(ImGuiIO& io,
|
||||
const std::span<const kernel::Resolution> options,
|
||||
xe::be<int32_t>& resolution,
|
||||
xe::be<uint32_t>& video_flags) {
|
||||
const char* preview = "Unknown";
|
||||
for (const auto& opt : options) {
|
||||
if (opt.to_host() == resolution.get()) {
|
||||
preview = opt.name_.c_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Resolution", preview)) {
|
||||
for (const auto& opt : options) {
|
||||
const bool selected = (opt.to_host() == resolution.get());
|
||||
if (ImGui::Selectable(opt.name_.c_str(), selected)) {
|
||||
resolution = opt.to_host();
|
||||
|
||||
if (opt.is_widescreen()) {
|
||||
video_flags = video_flags | static_cast<uint32_t>(
|
||||
kernel::X_VIDEO_FLAGS::Widescreen);
|
||||
} else {
|
||||
video_flags = video_flags & ~static_cast<uint32_t>(
|
||||
kernel::X_VIDEO_FLAGS::Widescreen);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTimezoneCombobox(ImGuiIO& io, kernel::XConfigData* xdata) {
|
||||
const kernel::TimeZone current_tz = {
|
||||
xdata->user.time_zone_bias, xdata->user.tz_std_name,
|
||||
xdata->user.tz_dlt_name, xdata->user.tz_std_date,
|
||||
xdata->user.tz_dlt_date, xdata->user.tz_std_bias,
|
||||
xdata->user.tz_dlt_bias};
|
||||
|
||||
size_t index = 0x19; // Index of GMT+00
|
||||
|
||||
auto it = std::find(kernel::kTimezones.cbegin(), kernel::kTimezones.cend(),
|
||||
current_tz);
|
||||
if (it != kernel::kTimezones.cend()) {
|
||||
index = std::distance(kernel::kTimezones.cbegin(), it);
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Timezone", kernel::kTimezones[index].name.c_str())) {
|
||||
for (size_t i = 0; i < kernel::kTimezones.size(); ++i) {
|
||||
const bool is_selected =
|
||||
(kernel::kTimezones[i] == kernel::kTimezones[index]);
|
||||
|
||||
if (ImGui::Selectable(kernel::kTimezones[i].name.c_str(), is_selected)) {
|
||||
index = i;
|
||||
|
||||
// Update timezone values
|
||||
const auto& tz = kernel::kTimezones[index];
|
||||
xdata->user.time_zone_bias = tz.timezone_bias;
|
||||
memcpy(xdata->user.tz_std_name.data(), tz.tz_std_name.data(), 4);
|
||||
memcpy(xdata->user.tz_dlt_name.data(), tz.tz_dlt_name.data(), 4);
|
||||
memcpy(xdata->user.tz_std_date.data(), tz.tz_std_date.data(), 4);
|
||||
memcpy(xdata->user.tz_dlt_date.data(), tz.tz_dlt_date.data(), 4);
|
||||
xdata->user.tz_std_bias = tz.tz_std_bias;
|
||||
xdata->user.tz_dlt_bias = tz.tz_dlt_bias;
|
||||
}
|
||||
if (is_selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool FlagCheckbox(const char* label, xe::be<T>& field, T value) {
|
||||
bool set = (field.get() & value) != 0;
|
||||
if (ImGui::Checkbox(label, &set)) {
|
||||
if (set) {
|
||||
field = field.get() | value;
|
||||
} else {
|
||||
field = field.get() & ~value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void ByteArray(const char* label, T* array, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
ImGui::SetNextItemWidth(ImGui::CalcTextSize("CC_").x);
|
||||
ImGui::InputScalar(fmt::format("##{}{}", label, i).c_str(),
|
||||
ImGuiDataType_U8, &array[i], nullptr, nullptr, "%02X");
|
||||
|
||||
if (i + 1 < count) {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroupBox(const char* label, auto draw_fn) {
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 text_size = ImGui::CalcTextSize(label);
|
||||
float border_offset = text_size.y * 0.5f;
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
// Push content down so it doesn't overlap the label
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + border_offset);
|
||||
ImGui::Indent(8.0f);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x - 16.0f, 0));
|
||||
ImGui::Spacing();
|
||||
draw_fn();
|
||||
ImGui::Spacing();
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::Unindent(8.0f);
|
||||
|
||||
// NOW we know the rect
|
||||
ImVec2 rect_min = ImGui::GetItemRectMin();
|
||||
ImVec2 rect_max = ImGui::GetItemRectMax();
|
||||
|
||||
// Expand rect a bit for padding
|
||||
rect_min.x -= 8.0f;
|
||||
rect_max.x += 8.0f;
|
||||
rect_max.y += style.ItemSpacing.y;
|
||||
|
||||
// Move the top of the border up to account for label offset
|
||||
rect_min.y -= border_offset;
|
||||
|
||||
ImU32 border_color = ImGui::GetColorU32(ImGuiCol_Border);
|
||||
float label_start = rect_min.x + 8.0f;
|
||||
float label_end = label_start + text_size.x + 4.0f;
|
||||
|
||||
// Top edge with gap for label
|
||||
draw_list->AddLine(ImVec2(rect_min.x, rect_min.y),
|
||||
ImVec2(label_start, rect_min.y), border_color);
|
||||
draw_list->AddLine(ImVec2(label_end, rect_min.y),
|
||||
ImVec2(rect_max.x, rect_min.y), border_color);
|
||||
// Left, right, bottom
|
||||
draw_list->AddLine(rect_min, ImVec2(rect_min.x, rect_max.y), border_color);
|
||||
draw_list->AddLine(ImVec2(rect_max.x, rect_min.y),
|
||||
ImVec2(rect_max.x, rect_max.y), border_color);
|
||||
draw_list->AddLine(ImVec2(rect_min.x, rect_max.y), rect_max, border_color);
|
||||
|
||||
// Label
|
||||
draw_list->AddText(ImVec2(label_start + 2.0f, rect_min.y - border_offset),
|
||||
ImGui::GetColorU32(ImGuiCol_Text), label);
|
||||
|
||||
ImGui::SetCursorPosY(rect_max.y + style.ItemSpacing.y);
|
||||
}
|
||||
|
||||
void ConsoleSettingsDialog::OnDraw(ImGuiIO& io) {
|
||||
ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(20, 20), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowBgAlpha(0.90f);
|
||||
bool dialog_open = true;
|
||||
if (!ImGui::Begin("Console settings", &dialog_open,
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_NoMove)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dialog_open) {
|
||||
Close();
|
||||
ImGui::End();
|
||||
emulator_window_.ToggleConsoleSettingsDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabBar("##Categories")) {
|
||||
if (ImGui::BeginTabItem("User")) {
|
||||
ImGui::BeginDisabled(emulator_window_.emulator()->is_title_open());
|
||||
ImGui::Dummy(ImVec2(2.f, 2.f));
|
||||
|
||||
GroupBox("Time", [&]() {
|
||||
DrawTimezoneCombobox(io, &xconfig_data_);
|
||||
|
||||
FlagCheckbox("Disable Daylight-Saving Time",
|
||||
xconfig_data_.user.retail_flags,
|
||||
static_cast<uint32_t>(kernel::X_RETAIL_FLAGS::DSTOff));
|
||||
|
||||
FlagCheckbox(
|
||||
"24H Time", xconfig_data_.user.retail_flags,
|
||||
static_cast<uint32_t>(kernel::X_RETAIL_FLAGS::TwentyFourHourClock));
|
||||
});
|
||||
|
||||
GroupBox("Locale", [&]() {
|
||||
DrawCombobox(io, "Language", kLanguageMap, xconfig_data_.user.language);
|
||||
DrawCombobox(io, "Country", kCountryMap, xconfig_data_.user.country);
|
||||
});
|
||||
|
||||
GroupBox("Profile", [&]() {
|
||||
DrawCombobox(io, "Default Profile", profiles_,
|
||||
xconfig_data_.user.default_profile);
|
||||
|
||||
FlagCheckbox("Parental Control",
|
||||
xconfig_data_.user.parental_control_flags,
|
||||
static_cast<uint8_t>(kernel::X_PC_FLAGS::PCEnabled));
|
||||
});
|
||||
|
||||
ImGui::Dummy(ImVec2(2.f, 2.f));
|
||||
|
||||
GroupBox("Retail Options", [&]() {
|
||||
FlagCheckbox("Dashboard Initialized", xconfig_data_.user.retail_flags,
|
||||
static_cast<uint32_t>(
|
||||
kernel::X_RETAIL_FLAGS::DashboardInitialized));
|
||||
FlagCheckbox(
|
||||
"IPTV Initialized", xconfig_data_.user.retail_flags,
|
||||
static_cast<uint32_t>(kernel::X_RETAIL_FLAGS::IPTVEnabled));
|
||||
FlagCheckbox(
|
||||
"DVR Initialized", xconfig_data_.user.retail_flags,
|
||||
static_cast<uint32_t>(kernel::X_RETAIL_FLAGS::IPTVDVREnabled));
|
||||
FlagCheckbox(
|
||||
"Kinect Initialized", xconfig_data_.user.retail_flags,
|
||||
static_cast<uint32_t>(kernel::X_RETAIL_FLAGS::KinectInitialized));
|
||||
});
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("System")) {
|
||||
ImGui::BeginDisabled(emulator_window_.emulator()->is_title_open());
|
||||
ImGui::Dummy(ImVec2(2.f, 2.f));
|
||||
|
||||
GroupBox("Video Options", [&]() {
|
||||
DrawCombobox(io, "AV Region", kAVRegion,
|
||||
xconfig_data_.secured.av_region);
|
||||
|
||||
DrawResolutionCombobox(
|
||||
io, {kernel::XVGAResolution.data(), kernel::XVGAResolution.size()},
|
||||
xconfig_data_.user.av_pack_hdmi_sz, xconfig_data_.user.video_flags);
|
||||
|
||||
const auto res =
|
||||
kernel::Resolution(xconfig_data_.user.av_pack_hdmi_sz.get());
|
||||
|
||||
ImGui::BeginDisabled(res.is_widescreen());
|
||||
FlagCheckbox("Widescreen", xconfig_data_.user.video_flags,
|
||||
static_cast<uint32_t>(kernel::X_VIDEO_FLAGS::Widescreen));
|
||||
ImGui::EndDisabled();
|
||||
});
|
||||
|
||||
GroupBox("Audio Options", [&]() {
|
||||
FlagCheckbox("Mono", xconfig_data_.user.audio_flags,
|
||||
static_cast<uint32_t>(kernel::X_AUDIO_FLAGS::AnalogMono));
|
||||
|
||||
FlagCheckbox(
|
||||
"Dolby Pro Logic", xconfig_data_.user.audio_flags,
|
||||
static_cast<uint32_t>(kernel::X_AUDIO_FLAGS::DolbyProLogic));
|
||||
|
||||
FlagCheckbox(
|
||||
"Dolby Digital", xconfig_data_.user.audio_flags,
|
||||
static_cast<uint32_t>(kernel::X_AUDIO_FLAGS::DolbyDigital));
|
||||
|
||||
FlagCheckbox("Dolby Digital WMA PRO", xconfig_data_.user.audio_flags,
|
||||
static_cast<uint32_t>(
|
||||
kernel::X_AUDIO_FLAGS::DolbyDigitalWithWMAPRO));
|
||||
|
||||
FlagCheckbox("Low Latency (unsupported)",
|
||||
xconfig_data_.user.audio_flags,
|
||||
static_cast<uint32_t>(kernel::X_AUDIO_FLAGS::LowLatency));
|
||||
|
||||
float volume = xconfig_data_.user.music_volume.get();
|
||||
if (ImGui::SliderFloat("Audio player volume", &volume, 0.0f, 1.0f,
|
||||
"%.2f")) {
|
||||
xconfig_data_.user.music_volume = volume;
|
||||
}
|
||||
});
|
||||
|
||||
GroupBox("Network", [&]() {
|
||||
if (ImGui::BeginTable("##NetworkTable", 2)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Text("MAC Address: ");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ByteArray("mac", xconfig_data_.secured.mac_address.data(),
|
||||
xconfig_data_.secured.mac_address.size());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Text("Network ID: ");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ByteArray("netid", xconfig_data_.secured.online_network_id.data(),
|
||||
xconfig_data_.secured.online_network_id.size());
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
});
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(2.f, 2.f));
|
||||
// Bottom
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::BeginDisabled(emulator_window_.emulator()->is_title_open());
|
||||
if (ImGui::Button("Save")) {
|
||||
SaveConfig();
|
||||
save_confirmation_disappearance_ = ImGui::GetTime() + 3.0;
|
||||
}
|
||||
|
||||
if (save_confirmation_disappearance_ > ImGui::GetTime()) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Settings Saved!");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
|
||||
ImGui::GetContentRegionAvail().x - 55.f);
|
||||
|
||||
if (ImGui::Button("Reset", ImVec2(55.f, 0.0f))) {
|
||||
xconfig_->SetDefaults();
|
||||
xconfig_data_ = *xconfig_->GetXConfig();
|
||||
save_confirmation_disappearance_ = ImGui::GetTime() + 3.0;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ConsoleSettingsDialog::SaveConfig() {
|
||||
xconfig_->WriteXConfig(&xconfig_data_);
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
} // namespace xe
|
||||
62
src/xenia/app/console_settings_dialog.h
Normal file
62
src/xenia/app/console_settings_dialog.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2026 Xenia Canary. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_APP_CONSOLE_SETTING_DIALOG_H_
|
||||
#define XENIA_APP_CONSOLE_SETTING_DIALOG_H_
|
||||
|
||||
#include "xenia/ui/imgui_dialog.h"
|
||||
#include "xenia/ui/imgui_drawer.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
|
||||
namespace xe {
|
||||
namespace app {
|
||||
|
||||
class EmulatorWindow;
|
||||
|
||||
class ConsoleSettingsDialog final : public ui::ImGuiDialog {
|
||||
public:
|
||||
ConsoleSettingsDialog(ui::ImGuiDrawer* imgui_drawer,
|
||||
EmulatorWindow& emulator_window,
|
||||
kernel::XConfig* xconfig)
|
||||
: ui::ImGuiDialog(imgui_drawer),
|
||||
emulator_window_(emulator_window),
|
||||
xconfig_(xconfig),
|
||||
xconfig_data_(*xconfig->GetXConfig()) {
|
||||
const auto profiles = emulator_window.emulator()
|
||||
->kernel_state()
|
||||
->xam_state()
|
||||
->profile_manager()
|
||||
->GetAccounts();
|
||||
|
||||
for (const auto& [xuid, profile] : *profiles) {
|
||||
profiles_.insert({xuid, profile.GetGamertagString()});
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnDraw(ImGuiIO& io) override;
|
||||
|
||||
private:
|
||||
void SaveConfig();
|
||||
|
||||
EmulatorWindow& emulator_window_;
|
||||
kernel::XConfig* xconfig_ = nullptr;
|
||||
kernel::XConfigData xconfig_data_{};
|
||||
std::map<uint64_t, std::string> profiles_;
|
||||
|
||||
// UI specific variables
|
||||
double save_confirmation_disappearance_ = 0.0;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
} // namespace xe
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,8 @@
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "xenia/app/console_settings_dialog.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
@@ -36,6 +38,7 @@
|
||||
#include "xenia/kernel/xam/profile_manager.h"
|
||||
#include "xenia/kernel/xam/xam_module.h"
|
||||
#include "xenia/kernel/xam/xam_state.h"
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
#include "xenia/ui/file_picker.h"
|
||||
#include "xenia/ui/graphics_provider.h"
|
||||
#include "xenia/ui/imgui_dialog.h"
|
||||
@@ -725,7 +728,8 @@ void EmulatorWindow::XMPConfigDialog::OnDraw(ImGuiIO& io) {
|
||||
volume_ =
|
||||
emulator_window_.emulator_->audio_media_player()->GetVolume()->load();
|
||||
|
||||
if (ImGui::SliderFloat("Audio player volume", &volume_, 0.0f, 1.0f)) {
|
||||
if (ImGui::SliderFloat("Audio player volume", &volume_, 0.0f, 1.0f,
|
||||
"%.2f")) {
|
||||
audio_player->SetVolume(volume_);
|
||||
}
|
||||
}
|
||||
@@ -882,6 +886,15 @@ bool EmulatorWindow::Initialize() {
|
||||
}
|
||||
main_menu->AddChild(std::move(xmp_menu));
|
||||
|
||||
// Console menu
|
||||
auto console_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Console");
|
||||
{
|
||||
console_menu->AddChild(MenuItem::Create(
|
||||
MenuItem::Type::kString, "&Open console settings", "",
|
||||
std::bind(&EmulatorWindow::ToggleConsoleSettingsDialog, this)));
|
||||
}
|
||||
main_menu->AddChild(std::move(console_menu));
|
||||
|
||||
// Help menu.
|
||||
auto help_menu = MenuItem::Create(MenuItem::Type::kPopup, "&Help");
|
||||
{
|
||||
@@ -1541,12 +1554,15 @@ void EmulatorWindow::GpuClearCaches() {
|
||||
emulator()->graphics_system()->ClearCaches();
|
||||
}
|
||||
|
||||
void EmulatorWindow::SetFullscreen(bool fullscreen) {
|
||||
if (window_->IsFullscreen() == fullscreen) {
|
||||
void EmulatorWindow::SetFullscreen(bool fullscreen_) {
|
||||
if (window_->IsFullscreen() == fullscreen_) {
|
||||
return;
|
||||
}
|
||||
window_->SetFullscreen(fullscreen);
|
||||
window_->SetCursorVisibility(fullscreen
|
||||
|
||||
OVERRIDE_bool(fullscreen, fullscreen_);
|
||||
|
||||
window_->SetFullscreen(fullscreen_);
|
||||
window_->SetCursorVisibility(fullscreen_
|
||||
? ui::Window::CursorVisibility::kAutoHidden
|
||||
: ui::Window::CursorVisibility::kVisible);
|
||||
}
|
||||
@@ -1596,6 +1612,20 @@ void EmulatorWindow::ToggleXMPConfigDialog() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::ToggleConsoleSettingsDialog() {
|
||||
if (!console_settings_dialog_) {
|
||||
console_settings_dialog_ =
|
||||
std::unique_ptr<ConsoleSettingsDialog>(new ConsoleSettingsDialog(
|
||||
imgui_drawer_.get(), *this, emulator_->kernel_state()->xconfig()));
|
||||
} else {
|
||||
if (console_settings_dialog_->IsClosing()) {
|
||||
console_settings_dialog_.release();
|
||||
} else {
|
||||
console_settings_dialog_.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::ToggleControllerVibration() {
|
||||
auto input_sys = emulator()->input_system();
|
||||
if (input_sys) {
|
||||
@@ -2341,6 +2371,10 @@ void EmulatorWindow::ClearDialogs() {
|
||||
display_config_dialog_.reset();
|
||||
}
|
||||
|
||||
if (console_settings_dialog_) {
|
||||
console_settings_dialog_.reset();
|
||||
}
|
||||
|
||||
imgui_drawer_.get()->ClearDialogs();
|
||||
emulator_->kernel_state()->xam_state()->xam_dialogs_shown_ = 0;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
namespace xe {
|
||||
namespace app {
|
||||
|
||||
class ConsoleSettingsDialog;
|
||||
|
||||
struct RecentTitleEntry {
|
||||
std::string title_name;
|
||||
std::filesystem::path path_to_file;
|
||||
@@ -94,6 +96,8 @@ class EmulatorWindow {
|
||||
|
||||
void ToggleProfilesConfigDialog();
|
||||
void ToggleXMPConfigDialog();
|
||||
void ToggleConsoleSettingsDialog();
|
||||
|
||||
void SetHotkeysState(bool enabled) { disable_hotkeys_ = !enabled; }
|
||||
|
||||
// Types of button functions for hotkeys.
|
||||
@@ -313,6 +317,7 @@ class EmulatorWindow {
|
||||
bool initializing_shader_storage_ = false;
|
||||
|
||||
std::unique_ptr<DisplayConfigDialog> display_config_dialog_;
|
||||
std::unique_ptr<ConsoleSettingsDialog> console_settings_dialog_;
|
||||
|
||||
// Storing pointers and toggling dialog state is useful for broadcasting
|
||||
// messages back to guest.
|
||||
|
||||
@@ -130,7 +130,8 @@ DECLARE_bool(debug);
|
||||
|
||||
DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
|
||||
|
||||
DECLARE_bool(widescreen);
|
||||
DECLARE_int32(window_size_x);
|
||||
DECLARE_int32(window_size_y);
|
||||
|
||||
namespace xe {
|
||||
namespace app {
|
||||
@@ -538,12 +539,10 @@ bool EmulatorApp::OnInitialize() {
|
||||
emulator_ =
|
||||
std::make_unique<Emulator>("", storage_root, content_root, cache_root);
|
||||
|
||||
// Determine window size based on user setting.
|
||||
auto res = xe::gpu::GraphicsSystem::GetInternalDisplayResolution();
|
||||
|
||||
// Main emulator display window.
|
||||
emulator_window_ = EmulatorWindow::Create(emulator_.get(), app_context(),
|
||||
res.first, res.second);
|
||||
emulator_window_ =
|
||||
EmulatorWindow::Create(emulator_.get(), app_context(),
|
||||
cvars::window_size_x, cvars::window_size_y);
|
||||
if (!emulator_window_) {
|
||||
XELOGE("Failed to create the main emulator window");
|
||||
return false;
|
||||
|
||||
@@ -27,8 +27,6 @@ extern "C" {
|
||||
} // extern "C"
|
||||
|
||||
DEFINE_bool(enable_xmp, true, "Enables Music Player playback.", "APU");
|
||||
DEFINE_int32(xmp_default_volume, 70,
|
||||
"Default music volume if game doesn't set it [0-100].", "APU");
|
||||
|
||||
namespace xe {
|
||||
namespace apu {
|
||||
@@ -246,7 +244,8 @@ void AudioMediaPlayer::Play() {
|
||||
OnStateChanged();
|
||||
|
||||
if (volume_ == 0.0f) {
|
||||
volume_ = cvars::xmp_default_volume / 100.0f;
|
||||
volume_ = kernel_state_->xconfig()->ReadSetting<float>(
|
||||
kernel::XCONFIG_USER_CATEGORY, kernel::XCONFIG_USER_MUSIC_VOLUME);
|
||||
}
|
||||
|
||||
// Always apply the stored volume to the newly created driver
|
||||
|
||||
@@ -84,8 +84,6 @@ DEFINE_bool(allow_game_relative_writes, false,
|
||||
"generating test data to compare with original hardware. ",
|
||||
"General");
|
||||
|
||||
DECLARE_int32(user_language);
|
||||
|
||||
DECLARE_bool(allow_plugins);
|
||||
|
||||
DEFINE_int32(priority_class, 0,
|
||||
@@ -1555,8 +1553,9 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
||||
kernel_state_->xam_state()->user_tracker()->AddTitleToPlayedList();
|
||||
|
||||
if (game_info_database_->IsValid()) {
|
||||
title_name_ = game_info_database_->GetTitleName(
|
||||
static_cast<XLanguage>(cvars::user_language));
|
||||
title_name_ = game_info_database_->GetTitleName(static_cast<XLanguage>(
|
||||
kernel_state_->xconfig()->ReadSetting<uint32_t>(
|
||||
kernel::XCONFIG_USER_CATEGORY, kernel::XCONFIG_USER_LANGUAGE)));
|
||||
XELOGI("Title name: {}", title_name_);
|
||||
|
||||
// Show achievments data
|
||||
|
||||
@@ -23,34 +23,10 @@
|
||||
#include "xenia/ui/window.h"
|
||||
#include "xenia/ui/windowed_app_context.h"
|
||||
|
||||
DEFINE_uint32(internal_display_resolution, 8,
|
||||
"Allow games that support different resolutions to render "
|
||||
"in a specific resolution.\n"
|
||||
"This is not guaranteed to work with all games or improve "
|
||||
"performance.\n"
|
||||
" 0=640x480\n"
|
||||
" 1=640x576\n"
|
||||
" 2=720x480\n"
|
||||
" 3=720x576\n"
|
||||
" 4=800x600\n"
|
||||
" 5=848x480\n"
|
||||
" 6=1024x768\n"
|
||||
" 7=1152x864\n"
|
||||
" 8=1280x720 (Default)\n"
|
||||
" 9=1280x768\n"
|
||||
" 10=1280x960\n"
|
||||
" 11=1280x1024\n"
|
||||
" 12=1360x768\n"
|
||||
" 13=1440x900\n"
|
||||
" 14=1680x1050\n"
|
||||
" 15=1920x540\n"
|
||||
" 16=1920x1080\n"
|
||||
" 17=internal_display_resolution_x/y",
|
||||
"Video");
|
||||
DEFINE_uint32(internal_display_resolution_x, 1280,
|
||||
DEFINE_uint32(custom_internal_display_resolution_x, 0,
|
||||
"Custom width. See internal_display_resolution. Range 1-1920.",
|
||||
"Video");
|
||||
DEFINE_uint32(internal_display_resolution_y, 720,
|
||||
DEFINE_uint32(custom_internal_display_resolution_y, 0,
|
||||
"Custom height. See internal_display_resolution. Range 1-1080.\n",
|
||||
"Video");
|
||||
|
||||
@@ -95,21 +71,6 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
|
||||
scaled_aspect_x_ = 16;
|
||||
scaled_aspect_y_ = 9;
|
||||
|
||||
auto custom_res_x = cvars::internal_display_resolution_x;
|
||||
auto custom_res_y = cvars::internal_display_resolution_y;
|
||||
if (!custom_res_x || custom_res_x > 1920 || !custom_res_y ||
|
||||
custom_res_y > 1080) {
|
||||
OVERRIDE_uint32(internal_display_resolution_x,
|
||||
internal_display_resolution_entries[8].first);
|
||||
OVERRIDE_uint32(internal_display_resolution_y,
|
||||
internal_display_resolution_entries[8].second);
|
||||
config::SaveConfig();
|
||||
xe::FatalError(fmt::format(
|
||||
"Invalid custom resolution specified: {}x{}\n"
|
||||
"Width must be between 1-1920.\nHeight must be between 1-1080.",
|
||||
custom_res_x, custom_res_y));
|
||||
}
|
||||
|
||||
if (with_presentation && provider_) {
|
||||
// Safe if either the UI thread call or the presenter creation fails.
|
||||
if (app_context_) {
|
||||
@@ -175,8 +136,15 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
|
||||
#endif
|
||||
|
||||
while (frame_limiter_worker_running_) {
|
||||
// If there is no title running then there is no need for guest
|
||||
// frame limiter thread.
|
||||
if (!kernel_state_->title_id()) {
|
||||
xe::threading::Sleep(std::chrono::milliseconds(100));
|
||||
continue;
|
||||
}
|
||||
|
||||
register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] +=
|
||||
GetInternalDisplayResolution().second;
|
||||
GetResolution().second;
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
if (cvars::vsync) {
|
||||
@@ -454,14 +422,23 @@ bool GraphicsSystem::Restore(ByteStream* stream) {
|
||||
return command_processor_->Restore(stream);
|
||||
}
|
||||
|
||||
std::pair<uint16_t, uint16_t> GraphicsSystem::GetInternalDisplayResolution() {
|
||||
if (cvars::internal_display_resolution >=
|
||||
internal_display_resolution_entries.size()) {
|
||||
return {cvars::internal_display_resolution_x,
|
||||
cvars::internal_display_resolution_y};
|
||||
std::pair<uint32_t, uint32_t> GraphicsSystem::GetResolution() const {
|
||||
if (!kernel_state_) {
|
||||
return {1280, 720};
|
||||
}
|
||||
return internal_display_resolution_entries
|
||||
[cvars::internal_display_resolution];
|
||||
|
||||
if (cvars::custom_internal_display_resolution_x != 0 &&
|
||||
cvars::custom_internal_display_resolution_y != 0) {
|
||||
return {cvars::custom_internal_display_resolution_x,
|
||||
cvars::custom_internal_display_resolution_y};
|
||||
}
|
||||
|
||||
const auto resolution =
|
||||
kernel::Resolution(kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
kernel::XCONFIG_USER_CATEGORY,
|
||||
kernel::XCONFIG_USER_AV_COMPOSITE_SCREENSZ));
|
||||
|
||||
return {resolution.width_, resolution.height_};
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
@@ -34,28 +34,6 @@ class Emulator;
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
constexpr std::array<std::pair<uint16_t, uint16_t>, 17>
|
||||
internal_display_resolution_entries = {{{640, 480},
|
||||
{640, 576},
|
||||
{720, 480},
|
||||
{720, 576},
|
||||
{800, 600},
|
||||
{848, 480},
|
||||
{1024, 768},
|
||||
{1152, 864},
|
||||
{1280, 720},
|
||||
{1280, 768},
|
||||
{1280, 960},
|
||||
{1280, 1024},
|
||||
{1360, 768},
|
||||
{1440, 900},
|
||||
{1680, 1050},
|
||||
{1920, 540},
|
||||
{1920, 1080}}};
|
||||
|
||||
constexpr std::array<std::pair<uint16_t, uint16_t>, 3>
|
||||
driver_display_resolution = {{{1440, 900}, {1280, 720}, {1680, 1050}}};
|
||||
|
||||
class CommandProcessor;
|
||||
|
||||
class GraphicsSystem {
|
||||
@@ -109,7 +87,7 @@ class GraphicsSystem {
|
||||
bool Save(ByteStream* stream);
|
||||
bool Restore(ByteStream* stream);
|
||||
|
||||
static std::pair<uint16_t, uint16_t> GetInternalDisplayResolution();
|
||||
std::pair<uint32_t, uint32_t> GetResolution() const;
|
||||
|
||||
std::pair<uint32_t, uint32_t> GetScaledAspectRatio() const {
|
||||
return {scaled_aspect_x_, scaled_aspect_y_};
|
||||
|
||||
@@ -13,4 +13,4 @@ DEFINE_bool(headless, false,
|
||||
"Don't display any UI, using defaults for prompts as needed.",
|
||||
"UI");
|
||||
DEFINE_bool(log_high_frequency_kernel_calls, false,
|
||||
"Log kernel calls with the kHighFrequency tag.", "Kernel");
|
||||
"Log kernel calls with the kHighFrequency tag.", "Logging");
|
||||
|
||||
@@ -64,6 +64,8 @@ KernelState::KernelState(Emulator* emulator)
|
||||
file_system_ = emulator->file_system();
|
||||
xam_state_ = std::make_unique<xam::XamState>(emulator, this);
|
||||
smc_ = std::make_unique<SystemManagementController>();
|
||||
xconfig_ =
|
||||
std::make_unique<XConfig>(emulator->storage_root() / "xconfig.settings");
|
||||
|
||||
InitializeKernelGuestGlobals();
|
||||
kernel_version_ = KernelVersion(cvars::kernel_build_version);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "xenia/kernel/xam/user_profile.h"
|
||||
#include "xenia/kernel/xam/xam_state.h"
|
||||
#include "xenia/kernel/xam/xdbf/spa_info.h"
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
#include "xenia/kernel/xevent.h"
|
||||
#include "xenia/vfs/virtual_file_system.h"
|
||||
|
||||
@@ -193,6 +194,8 @@ class KernelState {
|
||||
XmpVolumePatch* xmp_volume_patch() const { return xmp_volume_patch_.get(); }
|
||||
void InitXmpVolumePatch();
|
||||
|
||||
XConfig* xconfig() const { return xconfig_.get(); }
|
||||
|
||||
std::bitset<4> GetConnectedUsers() const;
|
||||
|
||||
// Access must be guarded by the global critical region.
|
||||
@@ -350,6 +353,7 @@ class KernelState {
|
||||
std::unique_ptr<xam::XamState> xam_state_;
|
||||
std::unique_ptr<SystemManagementController> smc_;
|
||||
std::unique_ptr<XmpVolumePatch> xmp_volume_patch_;
|
||||
std::unique_ptr<XConfig> xconfig_;
|
||||
|
||||
KernelVersion kernel_version_;
|
||||
|
||||
|
||||
@@ -169,6 +169,16 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
|
||||
args->unk1.get(), args->unk2.get(), args->unk3.get());
|
||||
return X_E_SUCCESS;
|
||||
}
|
||||
// Causes dashboard to correctly process language/region change. It does not
|
||||
// contain any buffer.
|
||||
case 0x8000000D: {
|
||||
const bool is_pc_enabled =
|
||||
(kernel_state_->xconfig()->ReadSetting<uint8_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_PC_FLAGS) &
|
||||
X_PC_FLAGS::PCEnabled) != 0;
|
||||
|
||||
return is_pc_enabled ? X_E_ACCESS_DENIED : X_E_SUCCESS;
|
||||
}
|
||||
}
|
||||
XELOGE(
|
||||
"Unimplemented XAM message app={:08X}, msg={:08X}, arg1={:08X}, "
|
||||
|
||||
@@ -349,7 +349,8 @@ void UserTracker::UpdateTitleGpdFile() {
|
||||
}
|
||||
|
||||
auto user_language = spa_data_->GetExistingLanguage(
|
||||
static_cast<XLanguage>(cvars::user_language));
|
||||
static_cast<XLanguage>(kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
kernel::XCONFIG_USER_CATEGORY, kernel::XCONFIG_USER_LANGUAGE)));
|
||||
|
||||
// First add achievements because of lowest ID
|
||||
for (const auto& entry : spa_data_->GetAchievements()) {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
DEFINE_bool(allow_avatar_initialization, false,
|
||||
"Enable Avatar Initialization\n"
|
||||
" Only set true when testing Avatar games. Certain games may\n"
|
||||
" require kinect implementation.",
|
||||
"Only set true when testing Avatar games. Certain games may crash "
|
||||
"due to requirement of full avatar implementation.",
|
||||
"Kernel");
|
||||
|
||||
namespace xe {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_memory.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_modules.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
#include "xenia/kernel/xenumerator.h"
|
||||
#include "xenia/kernel/xthread.h"
|
||||
#include "xenia/ui/imgui_dialog.h"
|
||||
@@ -45,8 +46,6 @@ DEFINE_int32(avpack, 8,
|
||||
" 7 = TV PAL-60\n"
|
||||
" 8 = HDMI (default)",
|
||||
"Video");
|
||||
DECLARE_uint32(audio_flag);
|
||||
|
||||
DEFINE_bool(staging_mode, 0,
|
||||
"Enables preview mode in dashboards to render debug information.",
|
||||
"Kernel");
|
||||
@@ -605,11 +604,11 @@ dword_result_t XGetAudioFlags_entry() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!cvars::audio_flag) {
|
||||
return 0x10000 | 0x1;
|
||||
}
|
||||
const auto audio_flags = kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY,
|
||||
XCONFIG_USER_CATEGORY_ENTRIES::XCONFIG_USER_AUDIO_FLAGS);
|
||||
|
||||
return cvars::audio_flag;
|
||||
return audio_flags ? audio_flags : 0x10000 | 0x1;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XGetAudioFlags, kNone, kImplemented);
|
||||
|
||||
@@ -764,6 +763,21 @@ void GetSystemTimeAsFileTime_entry(lpqword_t time_ptr,
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(GetSystemTimeAsFileTime, kNone, kImplemented);
|
||||
|
||||
dword_result_t XamIsIptvEnabled_entry() {
|
||||
const bool iptv_enabled =
|
||||
kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
X_CONFIG_CATEGORY::XCONFIG_USER_CATEGORY, XCONFIG_USER_RETAIL_FLAGS) &
|
||||
X_RETAIL_FLAGS::IPTVEnabled;
|
||||
|
||||
return !iptv_enabled ? X_E_FAIL : X_ERROR_SUCCESS;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamIsIptvEnabled, kNone, kImplemented);
|
||||
|
||||
dword_result_t XamLookupCommonStringByIndex_entry(dword_t string_index) {
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamLookupCommonStringByIndex, kNone, kImplemented);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "third_party/fmt/include/fmt/xchar.h"
|
||||
|
||||
DECLARE_int32(user_country);
|
||||
DECLARE_int32(user_language);
|
||||
// TODO(gibbed): put these forward decls in a header somewhere.
|
||||
|
||||
namespace xe {
|
||||
@@ -205,17 +203,14 @@ uint8_t xeXamGetLocaleFromCountry(uint8_t id) {
|
||||
// Helpers.
|
||||
|
||||
uint8_t xeXamGetLocaleEx(uint8_t max_country_id, uint8_t max_locale_id) {
|
||||
// TODO(gibbed): rework when XConfig is cleanly implemented.
|
||||
uint8_t country_id = static_cast<uint8_t>(cvars::user_country);
|
||||
/*if (XSUCCEEDED(xboxkrnl::xeExGetXConfigSetting(
|
||||
3, 14, &country_id, sizeof(country_id), nullptr))) {*/
|
||||
uint8_t country_id = kernel_state()->xconfig()->ReadSetting<uint8_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_COUNTRY);
|
||||
if (country_id <= max_country_id) {
|
||||
uint8_t locale_id = xeXamGetLocaleFromCountry(country_id);
|
||||
if (locale_id <= max_locale_id) {
|
||||
return locale_id;
|
||||
}
|
||||
}
|
||||
/*}*/
|
||||
|
||||
// couldn't find locale, fallback from game region.
|
||||
auto game_region = xeXGetGameRegion();
|
||||
@@ -529,7 +524,9 @@ uint32_t xeXGetGameRegion() {
|
||||
0x02FEu, 0x03FFu, 0x02FEu, 0x03FFu, 0x02FEu, 0x02FEu, 0xFFFFu, 0x03FFu,
|
||||
0x03FFu, 0x03FFu, 0x03FFu, 0x02FEu, 0x03FFu, 0x03FFu, 0x02FEu, 0x00FFu,
|
||||
0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu, 0x03FFu};
|
||||
auto country = static_cast<uint8_t>(cvars::user_country);
|
||||
auto country = kernel_state()->xconfig()->ReadSetting<uint8_t>(
|
||||
XCONFIG_USER_CATEGORY,
|
||||
XCONFIG_USER_CATEGORY_ENTRIES::XCONFIG_USER_COUNTRY);
|
||||
return country < xe::countof(table) ? table[country] : 0xFFFFu;
|
||||
}
|
||||
|
||||
@@ -537,7 +534,11 @@ dword_result_t XGetGameRegion_entry() { return xeXGetGameRegion(); }
|
||||
DECLARE_XAM_EXPORT1(XGetGameRegion, kNone, kStub);
|
||||
|
||||
XLanguage xeGetLanguage(bool extended_languages_support) {
|
||||
auto desired_language = static_cast<XLanguage>(cvars::user_language);
|
||||
auto desired_language =
|
||||
static_cast<XLanguage>(kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY,
|
||||
XCONFIG_USER_CATEGORY_ENTRIES::XCONFIG_USER_LANGUAGE));
|
||||
|
||||
uint32_t region = xeXGetGameRegion();
|
||||
auto max_languages = extended_languages_support ? XLanguage::kMaxLanguages
|
||||
: XLanguage::kSChinese;
|
||||
@@ -599,6 +600,24 @@ pointer_result_t XamGetLanguageTypefacePatch_entry(dword_t language) {
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamGetLanguageTypefacePatch, kNone, kStub);
|
||||
|
||||
dword_result_t XamGetCountry_entry() {
|
||||
return kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY,
|
||||
XCONFIG_USER_CATEGORY_ENTRIES::XCONFIG_USER_COUNTRY);
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamGetCountry, kNone, kSketchy);
|
||||
|
||||
dword_result_t XamSetCountry_entry(dword_t country) {
|
||||
const uint8_t country_real = country;
|
||||
|
||||
kernel_state()->xconfig()->WriteSetting(
|
||||
XCONFIG_USER_CATEGORY,
|
||||
XCONFIG_USER_CATEGORY_ENTRIES::XCONFIG_USER_COUNTRY, &country_real);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamSetCountry, kNone, kSketchy);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
@@ -19,12 +19,6 @@
|
||||
#include "xenia/ui/windowed_app_context.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
DEFINE_bool(allow_nui_initialization, false,
|
||||
"Enable NUI initialization\n"
|
||||
" Only set true when testing kinect games. Certain games may\n"
|
||||
" require avatar implementation.",
|
||||
"Kernel");
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
@@ -69,8 +63,14 @@ dword_result_t XamNuiGetDeviceStatus_entry(
|
||||
*/
|
||||
|
||||
status_ptr.Zero();
|
||||
status_ptr->status = cvars::allow_nui_initialization;
|
||||
return cvars::allow_nui_initialization ? X_ERROR_SUCCESS : 0xC0050006;
|
||||
|
||||
const bool kinect_initialized =
|
||||
kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
X_CONFIG_CATEGORY::XCONFIG_USER_CATEGORY, XCONFIG_USER_RETAIL_FLAGS) &
|
||||
X_RETAIL_FLAGS::KinectInitialized;
|
||||
|
||||
status_ptr->status = kinect_initialized;
|
||||
return kinect_initialized ? X_ERROR_SUCCESS : 0xC0050006;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamNuiGetDeviceStatus, kNone, kStub);
|
||||
|
||||
@@ -195,8 +195,12 @@ dword_result_t XamNuiIsDeviceReady_entry() {
|
||||
- 0x0004
|
||||
- 0x0040
|
||||
*/
|
||||
uint16_t device_state = cvars::allow_nui_initialization ? 1 : 0;
|
||||
return device_state >> 1 & 1;
|
||||
const bool kinect_initialized =
|
||||
kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
X_CONFIG_CATEGORY::XCONFIG_USER_CATEGORY, XCONFIG_USER_RETAIL_FLAGS) &
|
||||
X_RETAIL_FLAGS::KinectInitialized;
|
||||
|
||||
return kinect_initialized >> 1 & 1;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamNuiIsDeviceReady, kNone, kImplemented);
|
||||
|
||||
|
||||
@@ -988,7 +988,8 @@ DECLARE_XAM_EXPORT1(XamUserGetUserFlagsFromXUID, kUserProfiles, kImplemented);
|
||||
dword_result_t XamUserGetOnlineLanguageFromXUID_entry(qword_t xuid) {
|
||||
const auto& user = kernel_state()->xam_state()->GetUserProfile(xuid);
|
||||
if (!user) {
|
||||
return cvars::user_language;
|
||||
return kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_LANGUAGE);
|
||||
}
|
||||
return user->GetLanguage();
|
||||
}
|
||||
@@ -998,7 +999,8 @@ DECLARE_XAM_EXPORT1(XamUserGetOnlineLanguageFromXUID, kUserProfiles,
|
||||
dword_result_t XamUserGetOnlineCountryFromXUID_entry(qword_t xuid) {
|
||||
const auto& user = kernel_state()->xam_state()->GetUserProfile(xuid);
|
||||
if (!user) {
|
||||
return cvars::user_country;
|
||||
return kernel_state()->xconfig()->ReadSetting<uint8_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_COUNTRY);
|
||||
}
|
||||
return user->GetCountry();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
dword_result_t XAudioGetSpeakerConfig_entry(lpdword_t config_ptr) {
|
||||
*config_ptr = cvars::audio_flag;
|
||||
kernel_state()->xconfig()->ReadSetting(
|
||||
XCONFIG_USER_CATEGORY,
|
||||
XCONFIG_USER_CATEGORY_ENTRIES::XCONFIG_USER_AUDIO_FLAGS, config_ptr);
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(XAudioGetSpeakerConfig, kAudio, kImplemented);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
|
||||
DEFINE_bool(log_string_format_kernel_calls, false,
|
||||
"Log kernel calls with the kHighFrequency tag.", "Logging");
|
||||
"Log usage of print formatters like sprintf.", "Logging");
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
@@ -16,21 +16,10 @@
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_rtl.h"
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
DEFINE_int32(
|
||||
video_standard, 1,
|
||||
"Enables switching between different video signals.\n 1=NTSC\n "
|
||||
"2=NTSC-J\n 3=PAL\n",
|
||||
"Video");
|
||||
|
||||
DEFINE_bool(use_50Hz_mode, false, "Enables usage of PAL-50 mode.", "Video");
|
||||
DEFINE_bool(interlaced, false, "Toggles interlaced mode.", "Video");
|
||||
|
||||
// TODO: This is stored in XConfig somewhere, probably in video flags.
|
||||
DEFINE_bool(widescreen, true, "Toggles between 16:9 and 4:3 aspect ratio.",
|
||||
"Video");
|
||||
|
||||
// BT.709 on modern monitors and TVs looks the closest to the Xbox 360 connected
|
||||
// to an HDTV.
|
||||
DEFINE_uint32(kernel_display_gamma_type, 2,
|
||||
@@ -42,37 +31,22 @@ DEFINE_double(kernel_display_gamma_power, 2.22222233,
|
||||
"Display gamma to use with kernel_display_gamma_type 3.",
|
||||
"Kernel");
|
||||
|
||||
inline const static uint32_t GetVideoStandard() {
|
||||
if (cvars::video_standard < 1 || cvars::video_standard > 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return cvars::video_standard;
|
||||
}
|
||||
|
||||
inline const static float GetVideoRefreshRate() {
|
||||
return cvars::use_50Hz_mode ? 50.0f : 60.0f;
|
||||
}
|
||||
|
||||
inline const static std::pair<uint16_t, uint16_t> GetDisplayAspectRatio() {
|
||||
if (cvars::widescreen) {
|
||||
return {16, 9};
|
||||
}
|
||||
|
||||
return {4, 3};
|
||||
}
|
||||
|
||||
static std::pair<uint32_t, uint32_t> CalculateScaledAspectRatio(uint32_t fb_x,
|
||||
uint32_t fb_y) {
|
||||
static std::pair<uint32_t, uint32_t> CalculateScaledAspectRatio(
|
||||
uint32_t fb_x, uint32_t fb_y, bool forced_widescreen) {
|
||||
// Calculate the game's final aspect ratio as it would appear on a physical
|
||||
// TV.
|
||||
auto dar = GetDisplayAspectRatio();
|
||||
uint32_t display_x = dar.first;
|
||||
uint32_t display_y = dar.second;
|
||||
const auto res = xe::kernel::Resolution(fb_x, fb_y);
|
||||
|
||||
auto res = xe::gpu::GraphicsSystem::GetInternalDisplayResolution();
|
||||
uint32_t res_x = res.first;
|
||||
uint32_t res_y = res.second;
|
||||
uint32_t display_x = res.aspect_ratio().first;
|
||||
uint32_t display_y = res.aspect_ratio().second;
|
||||
|
||||
if (forced_widescreen) {
|
||||
display_x = 16;
|
||||
display_y = 9;
|
||||
}
|
||||
|
||||
uint32_t res_x = res.width_.get();
|
||||
uint32_t res_y = res.height_.get();
|
||||
|
||||
uint32_t x_factor = std::gcd(fb_x, res_x);
|
||||
res_x /= x_factor;
|
||||
@@ -103,6 +77,47 @@ namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
bool IsWidescreen(KernelState* kernel_state, Resolution res) {
|
||||
if (res.is_widescreen()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return kernel_state->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_VIDEO_FLAGS) &
|
||||
X_VIDEO_FLAGS::Widescreen;
|
||||
}
|
||||
|
||||
// Video standard only supports value from 1 to 3. PAL50 is not included here
|
||||
// and PAL50 is converted to PAL with 50Hz in GetVideoRefreshRate.
|
||||
X_AV_VIDEO_STANDARD GetVideoStandard(KernelState* kernel_state) {
|
||||
auto av_region = static_cast<X_AV_VIDEO_STANDARD>(
|
||||
(kernel_state->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_SECURED_CATEGORY, XCONFIG_SECURED_AV_REGION) &
|
||||
0xFF00) >>
|
||||
8);
|
||||
|
||||
if (av_region == X_AV_VIDEO_STANDARD::PAL_50) {
|
||||
av_region = X_AV_VIDEO_STANDARD::PAL;
|
||||
}
|
||||
|
||||
if (av_region < X_AV_VIDEO_STANDARD::NTSCM ||
|
||||
av_region > X_AV_VIDEO_STANDARD::PAL_50) {
|
||||
return X_AV_VIDEO_STANDARD::NTSCM;
|
||||
}
|
||||
|
||||
return av_region;
|
||||
}
|
||||
|
||||
float GetVideoRefreshRate(KernelState* kernel_state) {
|
||||
const bool is_50Hz =
|
||||
(kernel_state->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_SECURED_CATEGORY, XCONFIG_SECURED_AV_REGION) >>
|
||||
23) &
|
||||
0x1;
|
||||
|
||||
return !is_50Hz ? 60.0f : 50.0f;
|
||||
}
|
||||
|
||||
// https://web.archive.org/web/20150805074003/https://www.tweakoz.com/orkid/
|
||||
// http://www.tweakoz.com/orkid/dox/d3/d52/xb360init_8cpp_source.html
|
||||
// https://github.com/Free60Project/xenosfb/
|
||||
@@ -205,17 +220,25 @@ void VdQueryVideoMode(X_VIDEO_MODE* video_mode,
|
||||
// TODO(benvanik): get info from actual display.
|
||||
std::memset(video_mode, 0, sizeof(X_VIDEO_MODE));
|
||||
|
||||
auto display_res = gpu::GraphicsSystem::GetInternalDisplayResolution();
|
||||
// Later calculate if resolution is widescreen or not and apply flag
|
||||
// accordingly. Technically possible resolutions should depend on av_pack, but
|
||||
// we can ignore it.
|
||||
const auto resolution =
|
||||
Resolution(kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_AV_COMPOSITE_SCREENSZ));
|
||||
|
||||
video_mode->display_width = display_res.first;
|
||||
video_mode->display_height = display_res.second;
|
||||
const auto is_widescreen = IsWidescreen(kernel_state(), resolution);
|
||||
|
||||
video_mode->display_width = resolution.width_.get();
|
||||
video_mode->display_height = resolution.height_.get();
|
||||
video_mode->is_interlaced = cvars::interlaced;
|
||||
video_mode->is_widescreen = cvars::widescreen;
|
||||
video_mode->is_widescreen = is_widescreen;
|
||||
video_mode->is_hi_def = video_mode->display_width >= 0x500;
|
||||
video_mode->refresh_rate = GetVideoRefreshRate();
|
||||
video_mode->video_standard = GetVideoStandard();
|
||||
video_mode->refresh_rate = GetVideoRefreshRate(kernel_state());
|
||||
video_mode->video_standard =
|
||||
static_cast<uint32_t>(GetVideoStandard(kernel_state()));
|
||||
video_mode->pixel_rate = 0x8A;
|
||||
video_mode->widescreen_flag = cvars::widescreen ? 0x01 : 0x03;
|
||||
video_mode->widescreen_flag = is_widescreen ? 0x01 : 0x03;
|
||||
}
|
||||
|
||||
void VdQueryRealVideoMode_entry(pointer_t<X_VIDEO_MODE> video_mode) {
|
||||
@@ -370,7 +393,12 @@ dword_result_t VdInitializeScalerCommandBuffer_entry(
|
||||
|
||||
uint32_t fb_x = (scaled_output_wh >> 16) & 0xFFFF;
|
||||
uint32_t fb_y = scaled_output_wh & 0xFFFF;
|
||||
auto aspect = CalculateScaledAspectRatio(fb_x, fb_y);
|
||||
const bool forced_widescreen =
|
||||
kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
XCONFIG_USER_CATEGORY, XCONFIG_USER_VIDEO_FLAGS) &
|
||||
X_VIDEO_FLAGS::Widescreen;
|
||||
|
||||
auto aspect = CalculateScaledAspectRatio(fb_x, fb_y, forced_widescreen);
|
||||
|
||||
auto graphics_system = kernel_state()->emulator()->graphics_system();
|
||||
graphics_system->SetScaledAspectRatio(aspect.first, aspect.second);
|
||||
|
||||
@@ -7,295 +7,35 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_xconfig.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
DEFINE_int32(user_language, 1,
|
||||
"User language ID.\n"
|
||||
" 1=en 2=ja 3=de 4=fr 5=es 6=it 7=ko 8=zh\n"
|
||||
" 9=pt 11=pl 12=ru 13=sv 14=tr 15=nb 16=nl 17=zh",
|
||||
"XConfig");
|
||||
|
||||
DEFINE_int32(user_country, 103,
|
||||
"User country ID.\n"
|
||||
" 1=AE 2=AL 3=AM 4=AR 5=AT 6=AU 7=AZ 8=BE 9=BG\n"
|
||||
" 10=BH 11=BN 12=BO 13=BR 14=BY 15=BZ 16=CA 18=CH 19=CL\n"
|
||||
" 20=CN 21=CO 22=CR 23=CZ 24=DE 25=DK 26=DO 27=DZ 28=EC\n"
|
||||
" 29=EE 30=EG 31=ES 32=FI 33=FO 34=FR 35=GB 36=GE 37=GR\n"
|
||||
" 38=GT 39=HK 40=HN 41=HR 42=HU 43=ID 44=IE 45=IL 46=IN\n"
|
||||
" 47=IQ 48=IR 49=IS 50=IT 51=JM 52=JO 53=JP 54=KE 55=KG\n"
|
||||
" 56=KR 57=KW 58=KZ 59=LB 60=LI 61=LT 62=LU 63=LV 64=LY\n"
|
||||
" 65=MA 66=MC 67=MK 68=MN 69=MO 70=MV 71=MX 72=MY 73=NI\n"
|
||||
" 74=NL 75=NO 76=NZ 77=OM 78=PA 79=PE 80=PH 81=PK 82=PL\n"
|
||||
" 83=PR 84=PT 85=PY 86=QA 87=RO 88=RU 89=SA 90=SE 91=SG\n"
|
||||
" 92=SI 93=SK 95=SV 96=SY 97=TH 98=TN 99=TR 100=TT 101=TW\n"
|
||||
" 102=UA 103=US 104=UY 105=UZ 106=VE 107=VN 108=YE 109=ZA\n",
|
||||
"XConfig");
|
||||
|
||||
DEFINE_uint32(
|
||||
audio_flag, 0x00010001,
|
||||
"Audio Mode Analog.\n"
|
||||
" 0x00000001 = Dolby Pro Logic\n"
|
||||
" 0x00000002 = Analog Mono\n"
|
||||
"Audio Mode Digital.\n"
|
||||
" 0x00000000 = Digital Stereo (choose one of the above by itself)\n"
|
||||
" 0x00010000 = Dolby Digital\n"
|
||||
" 0x00030000 = Dolby Digital with WMA PRO\n"
|
||||
"Special Flags.\n"
|
||||
" 0x00000003 = Stereo Bypass\n"
|
||||
" 0x80000000 = Low Latency\n"
|
||||
" This Config requires you to pair an analog and digitial flag together\n"
|
||||
" while digital stereo only requires an analog flag. Bonus flags are\n"
|
||||
" optional. Ex) 0x00010001\n",
|
||||
"XConfig");
|
||||
|
||||
DECLARE_bool(widescreen);
|
||||
DECLARE_bool(use_50Hz_mode);
|
||||
DECLARE_int32(video_standard);
|
||||
DECLARE_uint32(internal_display_resolution);
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
X_STATUS xeExGetXConfigSetting(X_CONFIG_CATEGORY category, uint16_t setting,
|
||||
void* buffer, uint16_t buffer_size,
|
||||
uint16_t* required_size) {
|
||||
uint16_t setting_size = 0;
|
||||
alignas(uint32_t) uint8_t value[4];
|
||||
|
||||
// TODO(benvanik): have real structs here that just get copied from.
|
||||
// https://free60project.github.io/wiki/XConfig.html
|
||||
// https://github.com/oukiar/freestyledash/blob/master/Freestyle/Tools/Generic/ExConfig.h
|
||||
switch (category) {
|
||||
case XCONFIG_SECURED_CATEGORY:
|
||||
switch (setting) {
|
||||
case XCONFIG_SECURED_AV_REGION:
|
||||
setting_size = 4;
|
||||
switch (cvars::video_standard) {
|
||||
case 1: // NTSCM
|
||||
xe::store_and_swap<uint32_t>(value, X_AV_REGION::NTSCM);
|
||||
break;
|
||||
case 2: // NTSCJ
|
||||
xe::store_and_swap<uint32_t>(value, X_AV_REGION::NTSCJ);
|
||||
break;
|
||||
case 3: // PAL
|
||||
xe::store_and_swap<uint32_t>(value, cvars::use_50Hz_mode
|
||||
? X_AV_REGION::PAL_50
|
||||
: X_AV_REGION::PAL);
|
||||
break;
|
||||
default:
|
||||
xe::store_and_swap<uint32_t>(value, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XELOGW(
|
||||
"An unimplemented setting 0x{:04X} in XCONFIG SECURED CATEGORY",
|
||||
static_cast<uint16_t>(setting));
|
||||
assert_unhandled_case(setting);
|
||||
return X_STATUS_INVALID_PARAMETER_2;
|
||||
}
|
||||
break;
|
||||
case XCONFIG_USER_CATEGORY:
|
||||
switch (setting) {
|
||||
case XCONFIG_USER_TIME_ZONE_BIAS:
|
||||
case XCONFIG_USER_TIME_ZONE_STD_NAME:
|
||||
case XCONFIG_USER_TIME_ZONE_DLT_NAME:
|
||||
case XCONFIG_USER_TIME_ZONE_STD_DATE:
|
||||
case XCONFIG_USER_TIME_ZONE_DLT_DATE:
|
||||
case XCONFIG_USER_TIME_ZONE_STD_BIAS:
|
||||
case XCONFIG_USER_TIME_ZONE_DLT_BIAS:
|
||||
setting_size = 4;
|
||||
// TODO(benvanik): get this value.
|
||||
xe::store_and_swap<uint32_t>(value, 0);
|
||||
break;
|
||||
case XCONFIG_USER_LANGUAGE:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, cvars::user_language);
|
||||
break;
|
||||
case XCONFIG_USER_VIDEO_FLAGS:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, cvars::widescreen
|
||||
? X_VIDEO_FLAGS::Widescreen
|
||||
: X_VIDEO_FLAGS::RatioNormal);
|
||||
break;
|
||||
case XCONFIG_USER_AUDIO_FLAGS:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, cvars::audio_flag);
|
||||
break;
|
||||
case XCONFIG_USER_RETAIL_FLAGS:
|
||||
setting_size = 4;
|
||||
// TODO(benvanik): get this value.
|
||||
xe::store_and_swap<uint32_t>(value, 0x40);
|
||||
break;
|
||||
case XCONFIG_USER_COUNTRY:
|
||||
setting_size = 1;
|
||||
value[0] = static_cast<uint8_t>(cvars::user_country);
|
||||
break;
|
||||
case XCONFIG_USER_PC_FLAGS:
|
||||
setting_size = 1;
|
||||
// All related flags must be set for PC to function
|
||||
// Both flags set even when PC are off
|
||||
value[0] =
|
||||
X_PC_FLAGS::XBLAllowed | X_PC_FLAGS::XBLMembershipCreationAllowed;
|
||||
break;
|
||||
case XCONFIG_USER_AV_COMPONENT_SCREENSZ:
|
||||
setting_size = 4;
|
||||
// int16_t* value[2];
|
||||
if (XHDTVResolution.find(cvars::internal_display_resolution) !=
|
||||
XHDTVResolution.cend()) {
|
||||
xe::store_and_swap<int32_t>(
|
||||
value, XHDTVResolution.at(cvars::internal_display_resolution));
|
||||
} else {
|
||||
XELOGW("Resolution not supported for AV Component");
|
||||
xe::store_and_swap<int32_t>(value, 0);
|
||||
}
|
||||
break;
|
||||
case XCONFIG_USER_AV_VGA_SCREENSZ:
|
||||
setting_size = 4;
|
||||
// int16_t* value[2];
|
||||
if (XVGAResolution.find(cvars::internal_display_resolution) !=
|
||||
XVGAResolution.cend()) {
|
||||
xe::store_and_swap<int32_t>(
|
||||
value, XVGAResolution.at(cvars::internal_display_resolution));
|
||||
} else {
|
||||
XELOGW("Resolution not supported for VGA");
|
||||
xe::store_and_swap<int32_t>(value, 0);
|
||||
}
|
||||
break;
|
||||
case XCONFIG_USER_PC_GAME:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value,
|
||||
X_PC_GAMES_FLAGS::NoGameRestrictions);
|
||||
break;
|
||||
case XCONFIG_USER_PC_PASSWORD:
|
||||
setting_size = 4;
|
||||
std::memset(value, 0, 4);
|
||||
break;
|
||||
case XCONFIG_USER_PC_MOVIE:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value,
|
||||
X_PC_MOVIE_FLAGS::NoMovieRestrictions);
|
||||
break;
|
||||
case XCONFIG_USER_PC_GAME_RATING:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value,
|
||||
X_PC_GAME_RATING_FLAGS::DefaultGame);
|
||||
break;
|
||||
case XCONFIG_USER_PC_MOVIE_RATING:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value,
|
||||
X_PC_MOVIE_RATING_FLAGS::DefaultMovie);
|
||||
break;
|
||||
case XCONFIG_USER_PC_HINT:
|
||||
// ExSetXConfigSetting and ExGetXConfigSetting request size of 0x40
|
||||
setting_size = 0x40;
|
||||
store_and_swap<std::string>(value, "");
|
||||
break;
|
||||
case XCONFIG_USER_PC_HINT_ANSWER:
|
||||
setting_size = 0x20;
|
||||
store_and_swap<std::string>(value, "");
|
||||
break;
|
||||
case XCONFIG_USER_ARCADE_FLAGS:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, X_ARCADE_FLAGS::AutoDownloadOff);
|
||||
break;
|
||||
case XCONFIG_USER_PC_VERSION:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, X_PC_VERSION::VersionOne);
|
||||
break;
|
||||
case XCONFIG_USER_PC_TV:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, X_PC_TV::NoTVRestrictions);
|
||||
break;
|
||||
case XCONFIG_USER_PC_TV_RATING:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, X_PC_TV_RATING::DefaultTV);
|
||||
break;
|
||||
case XCONFIG_USER_PC_EXPLICIT_VIDEO:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(
|
||||
value, X_PC_EXPLICIT_VIDEO::ExplicitVideoAllowed);
|
||||
break;
|
||||
case XCONFIG_USER_PC_EXPLICIT_VIDEO_RATING:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(
|
||||
value, X_PC_EXPLICIT_VIDEO_RATING::ExplicitAllowed);
|
||||
break;
|
||||
case XCONFIG_USER_PC_UNRATED_VIDEO:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value,
|
||||
X_PC_EXPLICIT_UNRATED::UnratedALL);
|
||||
break;
|
||||
case XCONFIG_USER_PC_UNRATED_VIDEO_RATING:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(
|
||||
value, X_PC_EXPLICIT_UNRATED_RATING::DefaultExplicitUnrated);
|
||||
break;
|
||||
case XCONFIG_USER_VIDEO_OUTPUT_BLACK_LEVELS:
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, X_BLACK_LEVEL::LevelNormal);
|
||||
break;
|
||||
default:
|
||||
XELOGW("An unimplemented setting 0x{:04X} in XCONFIG USER CATEGORY",
|
||||
static_cast<uint16_t>(setting));
|
||||
assert_unhandled_case(setting);
|
||||
return X_STATUS_INVALID_PARAMETER_2;
|
||||
}
|
||||
break;
|
||||
case XCONFIG_CONSOLE_CATEGORY:
|
||||
switch (setting) {
|
||||
case XCONFIG_CONSOLE_SCREEN_SAVER:
|
||||
setting_size = 2;
|
||||
xe::store_and_swap<int16_t>(value, X_SCREENSAVER::ScreensaverOff);
|
||||
break;
|
||||
case XCONFIG_CONSOLE_AUTO_SHUT_OFF:
|
||||
setting_size = 2;
|
||||
xe::store_and_swap<int16_t>(value, X_AUTO_SHUTDOWN::AutoShutdownOff);
|
||||
break;
|
||||
case XCONFIG_CONSOLE_CAMERA_SETTINGS:
|
||||
// Camera Flags are added together and last byte is always 0x1
|
||||
setting_size = 4;
|
||||
xe::store_and_swap<uint32_t>(value, X_CAMERA_FLAGS::AutoAll);
|
||||
break;
|
||||
case XCONFIG_CONSOLE_KEYBOARD_LAYOUT:
|
||||
setting_size = 2;
|
||||
xe::store_and_swap<int16_t>(value,
|
||||
X_KEYBOARD_LAYOUT::KeyboardDefault);
|
||||
break;
|
||||
default:
|
||||
XELOGW(
|
||||
"An unimplemented setting 0x{:04X} in XCONFIG CONSOLE CATEGORY",
|
||||
static_cast<uint16_t>(setting));
|
||||
assert_unhandled_case(setting);
|
||||
return X_STATUS_INVALID_PARAMETER_2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XELOGW("An unimplemented category 0x{:04X}",
|
||||
static_cast<uint16_t>(category));
|
||||
assert_unhandled_case(category);
|
||||
return X_STATUS_INVALID_PARAMETER_1;
|
||||
X_STATUS xeExGetXConfigSetting(X_CONFIG_CATEGORY category,
|
||||
const uint16_t setting_id, void* buffer,
|
||||
uint16_t buffer_size, uint16_t* required_size) {
|
||||
if (!buffer && buffer_size) {
|
||||
return X_STATUS_INVALID_PARAMETER_3;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
if (buffer_size < setting_size) {
|
||||
if (buffer_size <
|
||||
kernel_state()->xconfig()->GetSettingSize(category, setting_id)) {
|
||||
return X_STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
std::memcpy(buffer, value, setting_size);
|
||||
} else {
|
||||
if (buffer_size) {
|
||||
return X_STATUS_INVALID_PARAMETER_3;
|
||||
}
|
||||
kernel_state()->xconfig()->ReadSetting(category, setting_id, buffer);
|
||||
}
|
||||
|
||||
if (required_size) {
|
||||
*required_size = setting_size;
|
||||
*required_size = static_cast<uint16_t>(
|
||||
kernel_state()->xconfig()->GetSettingSize(category, setting_id));
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
@@ -325,7 +65,11 @@ dword_result_t ExSetXConfigSetting_entry(word_t category, word_t setting,
|
||||
Handles settings the only have a single flag/value like
|
||||
XCONFIG_USER_VIDEO_FLAGS to swap
|
||||
*/
|
||||
XELOGI("ExSetXConfigSetting: category: 0X{:04x}, setting: 0X{:04x}",
|
||||
kernel_state()->xconfig()->WriteSetting(
|
||||
static_cast<X_CONFIG_CATEGORY>(category.value()), setting.value(),
|
||||
kernel_memory()->TranslateVirtual<void*>(buffer_ptr));
|
||||
|
||||
XELOGI("ExSetXConfigSetting: category: 0x{:04x}, setting: 0x{:04x}",
|
||||
static_cast<uint16_t>(category), static_cast<uint16_t>(setting));
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -339,6 +83,14 @@ dword_result_t ExReadModifyWriteXConfigSettingUlong_entry(word_t category,
|
||||
Handles settings with multiple flags like XCONFIG_USER_RETAIL_FLAGS and
|
||||
XCONFIG_CONSOLE_RETAIL_EX_FLAGS
|
||||
*/
|
||||
uint32_t value = kernel_state()->xconfig()->ReadSetting<uint32_t>(
|
||||
static_cast<X_CONFIG_CATEGORY>(category.value()), setting);
|
||||
|
||||
value = xe::byte_swap((value & bit_affected) | flag);
|
||||
|
||||
kernel_state()->xconfig()->WriteSetting(
|
||||
static_cast<X_CONFIG_CATEGORY>(category.value()), setting, &value);
|
||||
|
||||
XELOGI(
|
||||
"ExReadModifyWriteXConfigSettingUlong: category: 0x{:04x}, setting: "
|
||||
"{:04x}, changed bits: 0X{:08x}, setting flag 0X{:08x}",
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2025 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_XBOXKRNL_XBOXKRNL_XCONFIG_H_
|
||||
#define XENIA_KERNEL_XBOXKRNL_XBOXKRNL_XCONFIG_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
enum X_CONFIG_CATEGORY : uint16_t {
|
||||
XCONFIG_STATIC_CATEGORY = 0x00,
|
||||
XCONFIG_STATISTIC_CATEGORY = 0x01,
|
||||
XCONFIG_SECURED_CATEGORY = 0x02,
|
||||
XCONFIG_USER_CATEGORY = 0x03,
|
||||
XCONFIG_XNET_MACHINE_ACCOUNT_CATEGORY = 0x04,
|
||||
XCONFIG_XNET_PARAMETERS_CATEGORY = 0x05,
|
||||
XCONFIG_MEDIA_CENTER_CATEGORY = 0x06,
|
||||
XCONFIG_CONSOLE_CATEGORY = 0x07,
|
||||
XCONFIG_DVD_CATEGORY = 0x08,
|
||||
XCONFIG_IPTV_CATEGORY = 0x09,
|
||||
XCONFIG_SYSTEM_CATEGORY = 0x0A,
|
||||
XCONFIG_DEVKIT_CATEGORY = 0x0B
|
||||
};
|
||||
|
||||
enum XCONFIG_STATIC_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_STATIC_FIRST_POWER_ON_DATE = 0x01,
|
||||
XCONFIG_STATIC_SMC_CONFIG = 0x02
|
||||
};
|
||||
|
||||
enum XCONFIG_STATISTIC_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_STATISTICS_XUID_MAC_ADDRESS = 0x01,
|
||||
XCONFIG_STATISTICS_XUID_COUNT = 0x02,
|
||||
XCONFIG_STATISTICS_ODD_FAILURES = 0x03,
|
||||
XCONFIG_STATISTICS_HDD_SMART_DATA = 0x04,
|
||||
XCONFIG_STATISTICS_UEM_ERRORS = 0x05,
|
||||
XCONFIG_STATISTICS_FPM_ERRORS = 0x06,
|
||||
XCONFIG_STATISTICS_LAST_REPORT_TIME = 0x07,
|
||||
XCONFIG_STATISTICS_BUG_CHECK_DATA = 0x08,
|
||||
XCONFIG_STATISTICS_TEMPERATURE = 0x09,
|
||||
XCONFIG_STATISTICS_XEKEYS_WRITE_FAILURE = 0x0A
|
||||
};
|
||||
|
||||
enum XCONFIG_SECURED_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_SECURED_MAC_ADDRESS = 0x01,
|
||||
XCONFIG_SECURED_AV_REGION = 0x02,
|
||||
XCONFIG_SECURED_GAME_REGION = 0x03,
|
||||
XCONFIG_SECURED_DVD_REGION = 0x04,
|
||||
XCONFIG_SECURED_RESET_KEY = 0x05,
|
||||
XCONFIG_SECURED_SYSTEM_FLAGS = 0x06,
|
||||
XCONFIG_SECURED_POWER_MODE = 0x07,
|
||||
XCONFIG_SECURED_ONLINE_NETWORK_ID = 0x08,
|
||||
XCONFIG_SECURED_POWER_VCS_CONTROL = 0x09
|
||||
};
|
||||
|
||||
enum XCONFIG_USER_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_USER_TIME_ZONE_BIAS = 0x01,
|
||||
XCONFIG_USER_TIME_ZONE_STD_NAME = 0x02,
|
||||
XCONFIG_USER_TIME_ZONE_DLT_NAME = 0x03,
|
||||
XCONFIG_USER_TIME_ZONE_STD_DATE = 0x04,
|
||||
XCONFIG_USER_TIME_ZONE_DLT_DATE = 0x05,
|
||||
XCONFIG_USER_TIME_ZONE_STD_BIAS = 0x06,
|
||||
XCONFIG_USER_TIME_ZONE_DLT_BIAS = 0x07,
|
||||
XCONFIG_USER_DEFAULT_PROFILE = 0x08,
|
||||
XCONFIG_USER_LANGUAGE = 0x09,
|
||||
XCONFIG_USER_VIDEO_FLAGS = 0x0A,
|
||||
XCONFIG_USER_AUDIO_FLAGS = 0x0B,
|
||||
XCONFIG_USER_RETAIL_FLAGS = 0x0C,
|
||||
XCONFIG_USER_DEVKIT_FLAGS = 0x0D,
|
||||
XCONFIG_USER_COUNTRY = 0x0E,
|
||||
XCONFIG_USER_PC_FLAGS = 0x0F,
|
||||
XCONFIG_USER_SMB_CONFIG = 0x10,
|
||||
XCONFIG_USER_LIVE_PUID = 0x11,
|
||||
XCONFIG_USER_LIVE_CREDENTIALS = 0x12,
|
||||
XCONFIG_USER_AV_COMPOSITE_SCREENSZ = 0x13,
|
||||
XCONFIG_USER_AV_COMPONENT_SCREENSZ = 0x14,
|
||||
XCONFIG_USER_AV_VGA_SCREENSZ = 0x15,
|
||||
XCONFIG_USER_PC_GAME = 0x16,
|
||||
XCONFIG_USER_PC_PASSWORD = 0x17,
|
||||
XCONFIG_USER_PC_MOVIE = 0x18,
|
||||
XCONFIG_USER_PC_GAME_RATING = 0x19,
|
||||
XCONFIG_USER_PC_MOVIE_RATING = 0x1A,
|
||||
XCONFIG_USER_PC_HINT = 0x1B,
|
||||
XCONFIG_USER_PC_HINT_ANSWER = 0x1C,
|
||||
XCONFIG_USER_PC_OVERRIDE = 0x1D,
|
||||
XCONFIG_USER_MUSIC_PLAYBACK_MODE = 0x1E,
|
||||
XCONFIG_USER_MUSIC_VOLUME = 0x1F,
|
||||
XCONFIG_USER_MUSIC_FLAGS = 0x20,
|
||||
XCONFIG_USER_ARCADE_FLAGS = 0x21,
|
||||
XCONFIG_USER_PC_VERSION = 0x22,
|
||||
XCONFIG_USER_PC_TV = 0x23,
|
||||
XCONFIG_USER_PC_TV_RATING = 0x24,
|
||||
XCONFIG_USER_PC_EXPLICIT_VIDEO = 0x25,
|
||||
XCONFIG_USER_PC_EXPLICIT_VIDEO_RATING = 0x26,
|
||||
XCONFIG_USER_PC_UNRATED_VIDEO = 0x27,
|
||||
XCONFIG_USER_PC_UNRATED_VIDEO_RATING = 0x28,
|
||||
XCONFIG_USER_VIDEO_OUTPUT_BLACK_LEVELS = 0x29,
|
||||
XCONFIG_USER_VIDEO_PLAYER_DISPLAY_MODE = 0x2A,
|
||||
XCONFIG_USER_ALTERNATE_VIDEO_TIMING_ID = 0x2B,
|
||||
XCONFIG_USER_VIDEO_DRIVER_OPTIONS = 0x2C,
|
||||
XCONFIG_USER_MUSIC_UI_FLAGS = 0x2D,
|
||||
XCONFIG_USER_VIDEO_MEDIA_SOURCE_TYPE = 0x2E,
|
||||
XCONFIG_USER_MUSIC_MEDIA_SOURCE_TYPE = 0x2F,
|
||||
XCONFIG_USER_PHOTO_MEDIA_SOURCE_TYPE = 0x30
|
||||
};
|
||||
|
||||
enum XCONFIG_XNET_CATEGORY_ENTRIES : uint8_t { XCONFIG_XNET_DATA = 0x01 };
|
||||
|
||||
enum XCONFIG_MEDIA_CENTER_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_MEDIA_CENTER_MEDIA_PLAYER = 0x01,
|
||||
XCONFIG_MEDIA_CENTER_XESLED_VERSION = 0x02,
|
||||
XCONFIG_MEDIA_CENTER_XESLED_TRUST_SECRET = 0x03,
|
||||
XCONFIG_MEDIA_CENTER_XESLED_TRUST_CODE = 0x04,
|
||||
XCONFIG_MEDIA_CENTER_XESLED_HOST_ID = 0x05,
|
||||
XCONFIG_MEDIA_CENTER_XESLED_KEY = 0x06,
|
||||
XCONFIG_MEDIA_CENTER_XESLED_HOST_MAC_ADDRESS = 0x07,
|
||||
XCONFIG_MEDIA_CENTER_SERVER_UUID = 0x08,
|
||||
XCONFIG_MEDIA_CENTER_SERVER_NAME = 0x09,
|
||||
XCONFIG_MEDIA_CENTER_SERVER_FLAG = 0x0A
|
||||
};
|
||||
|
||||
enum XCONFIG_CONSOLE_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_CONSOLE_SCREEN_SAVER = 0x01,
|
||||
XCONFIG_CONSOLE_AUTO_SHUT_OFF = 0x02,
|
||||
XCONFIG_CONSOLE_WIRELESS_SETTINGS = 0x03,
|
||||
XCONFIG_CONSOLE_CAMERA_SETTINGS = 0x04,
|
||||
XCONFIG_CONSOLE_PLAYTIMERDATA = 0x05,
|
||||
XCONFIG_CONSOLE_MEDIA_DISABLEAUTOLAUNCH = 0x06,
|
||||
XCONFIG_CONSOLE_KEYBOARD_LAYOUT = 0x07,
|
||||
XCONFIG_CONSOLE_PC_TITLE_EXEMPTIONS = 0x08,
|
||||
XCONFIG_CONSOLE_NUI = 0x09,
|
||||
XCONFIG_CONSOLE_VOICE = 0x0A,
|
||||
XCONFIG_CONSOLE_RETAIL_EX_FLAGS = 0x0B,
|
||||
XCONFIG_CONSOLE_DASH_FIRST_USE_TUTORIAL_FLAGS = 0x0C,
|
||||
XCONFIG_CONSOLE_TV_DIAGONAL_SIZE_IN_CM = 0x0D,
|
||||
XCONFIG_CONSOLE_NETWORKSTORAGEDEVICE_SERIALNUMBER = 0x0E,
|
||||
XCONFIG_CONSOLE_DISCOVERABLE = 0x0F,
|
||||
XCONFIG_CONSOLE_LIVE_TV_PROVIDER = 0x10
|
||||
};
|
||||
|
||||
enum XCONFIG_DVD_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_DVD_VOLUME_ID = 0x01,
|
||||
XCONFIG_DVD_BOOKMARK = 0x02
|
||||
};
|
||||
|
||||
enum XCONFIG_IPTV_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_IPTV_SERVICE_PROVIDER_NAME = 0x01,
|
||||
XCONFIG_IPTV_PROVISIONING_SERVER_URL = 0x02,
|
||||
XCONFIG_IPTV_SUPPORT_INFO = 0x03,
|
||||
XCONFIG_IPTV_BOOTSTRAP_SERVER_URL = 0x04
|
||||
};
|
||||
|
||||
enum XCONFIG_SYSTEM_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_SYSTEM_ALARM_TIME = 0x01,
|
||||
XCONFIG_SYSTEM_PREVIOUS_FLASH_VERSION = 0x02
|
||||
};
|
||||
|
||||
enum XCONFIG_DEVKIT_CATEGORY_ENTRIES : uint8_t {
|
||||
XCONFIG_DEVKIT_USBD_ROOT_HUB_PORT_DISABLE_MASK = 0x01,
|
||||
XCONFIG_DEVKIT_XAM_FEATURE_ENABLE_DISABLE_MASK = 0x02,
|
||||
XCONFIG_DEVKIT_KIOSK_ID = 0x03
|
||||
};
|
||||
|
||||
// XCONFIG_SECURED_AV_REGION
|
||||
enum X_AV_REGION : uint32_t {
|
||||
NTSCM = 0x00400100,
|
||||
NTSCJ = 0x00400200,
|
||||
PAL = 0x00400400,
|
||||
PAL_50 = 0x00800300,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_VIDEO_FLAGS
|
||||
enum X_VIDEO_FLAGS : uint32_t {
|
||||
RatioNormal = 0x00000000,
|
||||
Widescreen = 0x00010000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_AV_COMPONENT_SCREENSZ
|
||||
const static std::map<uint32_t, int32_t> XHDTVResolution = {
|
||||
{0, 0x028001E0}, // 480p
|
||||
{8, 0x050002D0}, // 720p, always widescreen
|
||||
{16, 0x07800438}, // 1080, interlaced added in 1888, always widescreen
|
||||
};
|
||||
|
||||
// XCONFIG_USER_AV_COMPONENT_SCREENSZ
|
||||
const static std::map<uint32_t, int32_t> XVGAResolution = {
|
||||
// Existed since 1888
|
||||
{0, 0x028001E0}, // 680x480
|
||||
{5, 0x035001E0}, // 848x480
|
||||
{6, 0x04000300}, // 1024x768
|
||||
{8, 0x050002D0}, // 1280x720
|
||||
{9, 0x05000300}, // 1280x768
|
||||
{12, 0x05500300}, // 1360x768
|
||||
// added in later Versions
|
||||
{11, 0x05000400}, // 1280x1024
|
||||
{13, 0x05A00384}, // 1440x900
|
||||
{14, 0x0690041A}, // 1680x1050
|
||||
{16, 0x07800438}, // 1920x1080
|
||||
};
|
||||
|
||||
// XCONFIG_USER_AUDIO_FLAGS
|
||||
enum X_AUDIO_FLAGS : uint32_t {
|
||||
// Audio Mode Analog
|
||||
DolbyProLogic = 0x00000001,
|
||||
AnalogMono = 0x00000002,
|
||||
// Audio Mode Digital
|
||||
DigitalStereo = 0x00000000,
|
||||
DolbyDigital = 0x00010000,
|
||||
DolbyDigitalWithWMAPRO = 0x00030000,
|
||||
// Special Flags
|
||||
StereoBypass = 0x00000003,
|
||||
LowLatency = 0x80000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_RETAIL_FLAGS
|
||||
enum X_RETAIL_FLAGS : uint32_t {
|
||||
// Clock
|
||||
DSTOff = 0x00000002,
|
||||
TwentyFourHourClock = 0x00000008,
|
||||
|
||||
// Startup
|
||||
DashboardStartup = 0x00000080,
|
||||
IPTVStartup = 0x00000800,
|
||||
DiscStartup = 0x00002000,
|
||||
MCXDownloaderStartup = 0x00020000,
|
||||
// IPTV
|
||||
IPTVEnabled = 0x00001000,
|
||||
IPTVDVRENABLED = 0x00080000,
|
||||
IPTVDisabled = 0x02000000,
|
||||
// Kinect
|
||||
KinectInitialized = 0x20000000,
|
||||
KinectDisabled = 0x80000000,
|
||||
|
||||
// Other
|
||||
DashboardInitialized = 0x00000040,
|
||||
BackgroundDownloadOn = 0x00010000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_FLAGS
|
||||
enum X_PC_FLAGS : uint8_t {
|
||||
XBLAllowed = 0x01,
|
||||
XBLMembershipCreationAllowed = 0x02,
|
||||
XboxOneGameAllowed = 0x04,
|
||||
PCEnabled = 0x80,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_GAMES
|
||||
enum X_PC_GAMES_FLAGS : uint32_t {
|
||||
EarlyChildhoodMax = 0x00000000,
|
||||
EveryoneMax = 0x00000002,
|
||||
Everyone_10Max = 0x00000004,
|
||||
TeenMax = 0x00000006,
|
||||
MatureMax = 0x00000008,
|
||||
NoGameRestrictions = 0x000000FF,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_PASSWORD
|
||||
enum X_PC_PASSWORD_FLAGS : uint32_t {
|
||||
XButton = 0x00000001,
|
||||
YButton = 0x00000002,
|
||||
LeftButton = 0x00000003,
|
||||
RightButton = 0x00000004,
|
||||
UPButton = 0x00000005,
|
||||
DownButton = 0x00000006,
|
||||
LTButton = 0x00000009,
|
||||
RTButton = 0x0000000A,
|
||||
LBButton = 0x0000000B,
|
||||
RBButton = 0x0000000C,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_MOVIE
|
||||
enum X_PC_MOVIE_FLAGS : uint32_t {
|
||||
GeneralAudiences = 0x00000001,
|
||||
ParentalGuidance = 0x00000003,
|
||||
ParentalGuidance13 = 0x00000004,
|
||||
Restricted = 0x00000006,
|
||||
NoMovieRestrictions = 0x000000FF,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_GAME_RATING
|
||||
enum X_PC_GAME_RATING_FLAGS : uint32_t {
|
||||
DefaultGame = 0x00000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_MOVIE_RATING
|
||||
enum X_PC_MOVIE_RATING_FLAGS : uint32_t {
|
||||
DefaultMovie = 0x00000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_ARCADE_FLAGS
|
||||
enum X_ARCADE_FLAGS : uint32_t {
|
||||
AutoDownloadOff = 0x00000000,
|
||||
AutoDownloadNewReleases = 0x00000001,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_VERSION
|
||||
enum X_PC_VERSION : uint32_t {
|
||||
VersionOne = 0x00000001,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_TV
|
||||
enum X_PC_TV : uint32_t {
|
||||
TVG = 0X00000006,
|
||||
TVPG = 0X00000008,
|
||||
TV14 = 0X0000000a,
|
||||
TVMatureAudience = 0x0000000C,
|
||||
NoTVRestrictions = 0X000000FF,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_TV_RATING
|
||||
enum X_PC_TV_RATING : uint32_t {
|
||||
DefaultTV = 0X00000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_EXPLICIT_VIDEO
|
||||
enum X_PC_EXPLICIT_VIDEO : uint32_t {
|
||||
ExplicitVideoAllowed = 0X000000FF,
|
||||
ExplicitVideoBanned = 0X00000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_EXPLICIT_VIDEO_RATING
|
||||
enum X_PC_EXPLICIT_VIDEO_RATING : uint32_t {
|
||||
ExplicitAllowed = 0X00000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_UNRATED_VIDEO
|
||||
enum X_PC_EXPLICIT_UNRATED : uint32_t {
|
||||
ExplicitUnratedBanned = 0X00000000,
|
||||
UnratedALL = 0X000000FF,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_PC_UNRATED_VIDEO_RATING
|
||||
enum X_PC_EXPLICIT_UNRATED_RATING : uint32_t {
|
||||
DefaultExplicitUnrated = 0X00000000,
|
||||
};
|
||||
|
||||
// XCONFIG_USER_VIDEO_OUTPUT_BLACK_LEVELS
|
||||
enum X_BLACK_LEVEL : uint32_t {
|
||||
High = 0x00000100,
|
||||
Intermediate = 0x00000200,
|
||||
LevelNormal = 0x00000300,
|
||||
};
|
||||
|
||||
// XCONFIG_CONSOLE_SCREENSAVER
|
||||
enum X_SCREENSAVER : uint32_t {
|
||||
ScreensaverOn = 0x000A,
|
||||
ScreensaverOff = 0x1000,
|
||||
};
|
||||
|
||||
// XCONFIG_CONSOLE_AUTO_SHUTDOWN
|
||||
enum X_AUTO_SHUTDOWN : uint32_t {
|
||||
AutoShutdownOff = 0x0000,
|
||||
AutoShutdownOneHr = 0x003C,
|
||||
AutoShutdownSixHr = 0x0168,
|
||||
};
|
||||
|
||||
// XCONFIG_CONSOLE_CAMERA_SETTINGS
|
||||
enum X_CAMERA_FLAGS : uint32_t {
|
||||
// Room
|
||||
RoomAuto = 0x00000000,
|
||||
DarkWall = 0x00000001,
|
||||
LightWall = 0x00000002,
|
||||
// Lighting
|
||||
LightingAuto = 0x00000000,
|
||||
Incandescent = 0x00000004,
|
||||
Flourescent = 0x00000008,
|
||||
Daylight = 0x0000000C,
|
||||
// Flourescent Anti-Flicker
|
||||
AntiFlickerAuto = 0x00000000,
|
||||
AntiFlickerOn = 0x00000001,
|
||||
AntiFlickerOff = 0x00000002,
|
||||
// Default
|
||||
AutoAll = 0x00000001,
|
||||
};
|
||||
|
||||
// XCONFIG_CONSOLE_KEYBOARD_LAYOUT
|
||||
enum X_KEYBOARD_LAYOUT : uint16_t {
|
||||
KeyboardDefault = 0x0000,
|
||||
EnglishQWERTY = 0x0001,
|
||||
};
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_XBOXKRNL_XBOXKRNL_XCONFIG_H_
|
||||
174
src/xenia/kernel/xconfig.cc
Normal file
174
src/xenia/kernel/xconfig.cc
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2026 Xenia Canary. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/xconfig.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
#include "xenia/base/filesystem.h"
|
||||
|
||||
#include "xenia/base/byte_order.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
XConfig::XConfig(const std::filesystem::path& xconfig_path)
|
||||
: file_path_(xconfig_path) {
|
||||
if (!std::filesystem::exists(xconfig_path)) {
|
||||
SetDefaults();
|
||||
|
||||
if (xe::filesystem::CreateEmptyFile(xconfig_path)) {
|
||||
FlushToFile();
|
||||
}
|
||||
}
|
||||
|
||||
FILE* file = xe::filesystem::OpenFile(xconfig_path, "rb");
|
||||
|
||||
if (!file) {
|
||||
SetDefaults();
|
||||
return;
|
||||
}
|
||||
|
||||
fread(&xconfig_data_, sizeof(XConfigData), 1, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void XConfig::ReadSetting(const X_CONFIG_CATEGORY category,
|
||||
const uint16_t setting_id, void* buffer) {
|
||||
const auto setting = FindField(category, setting_id);
|
||||
|
||||
if (!setting) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<xe_mutex> lock(lock_);
|
||||
std::memcpy(buffer, CategoryBase(category) + setting->block_offset,
|
||||
setting->size);
|
||||
}
|
||||
|
||||
void XConfig::WriteSetting(const X_CONFIG_CATEGORY category,
|
||||
const uint16_t setting_id, const void* buffer) {
|
||||
const auto setting = FindField(category, setting_id);
|
||||
|
||||
if (!setting) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<xe_mutex> lock(lock_);
|
||||
std::memcpy(CategoryBase(category) + setting->block_offset, buffer,
|
||||
setting->size);
|
||||
|
||||
FlushToFile();
|
||||
}
|
||||
|
||||
uint16_t XConfig::GetSettingSize(const X_CONFIG_CATEGORY category,
|
||||
const uint16_t setting_id) {
|
||||
const auto setting = FindField(category, setting_id);
|
||||
|
||||
if (!setting) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return setting->size;
|
||||
}
|
||||
|
||||
void XConfig::WriteXConfig(const XConfigData* data) {
|
||||
xconfig_data_ = *data;
|
||||
FlushToFile();
|
||||
}
|
||||
|
||||
void XConfig::SetDefaults() {
|
||||
xconfig_data_ = {};
|
||||
|
||||
xconfig_data_.secured.av_region = X_AV_REGION::NTSCM;
|
||||
xconfig_data_.user.language = static_cast<uint32_t>(XLanguage::kEnglish);
|
||||
xconfig_data_.user.country =
|
||||
static_cast<uint8_t>(XOnlineCountry::kUnitedStates);
|
||||
xconfig_data_.user.audio_flags = DolbyDigital | DolbyProLogic;
|
||||
xconfig_data_.user.av_pack_hdmi_sz = XHDTVResolution.at(1).to_host();
|
||||
xconfig_data_.user.av_pack_component_sz = XHDTVResolution.at(1).to_host();
|
||||
xconfig_data_.user.av_pack_vga_sz = XVGAResolution.at(3).to_host();
|
||||
xconfig_data_.user.retail_flags = DashboardInitialized;
|
||||
xconfig_data_.user.video_flags = RatioNormal;
|
||||
xconfig_data_.user.parental_control_flags =
|
||||
XBLAllowed | XBLMembershipCreationAllowed;
|
||||
xconfig_data_.user.parental_control_game = NoGameRestrictions;
|
||||
xconfig_data_.user.music_volume = 0.7f;
|
||||
|
||||
const auto& tz = kTimezones[0x19];
|
||||
|
||||
xconfig_data_.user.time_zone_bias = tz.timezone_bias;
|
||||
memcpy(xconfig_data_.user.tz_std_name.data(), tz.tz_std_name.data(), 4);
|
||||
memcpy(xconfig_data_.user.tz_dlt_name.data(), tz.tz_dlt_name.data(), 4);
|
||||
memcpy(xconfig_data_.user.tz_std_date.data(), tz.tz_std_date.data(), 4);
|
||||
memcpy(xconfig_data_.user.tz_dlt_date.data(), tz.tz_dlt_date.data(), 4);
|
||||
xconfig_data_.user.tz_std_bias = tz.tz_std_bias;
|
||||
xconfig_data_.user.tz_dlt_bias = tz.tz_dlt_bias;
|
||||
}
|
||||
|
||||
void XConfig::FlushToFile() {
|
||||
if (!std::filesystem::exists(file_path_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* file = xe::filesystem::OpenFile(file_path_, "wb");
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&xconfig_data_, 1, sizeof(XConfigData), file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
const XConfig::FieldDescriptor* XConfig::FindField(X_CONFIG_CATEGORY category,
|
||||
uint16_t setting) {
|
||||
auto it = std::ranges::find_if(kFields, [&](const FieldDescriptor& f) {
|
||||
return f.category == category && f.setting == setting;
|
||||
});
|
||||
|
||||
return it == std::ranges::end(kFields) ? nullptr : &*it;
|
||||
}
|
||||
|
||||
uint8_t* XConfig::CategoryBase(X_CONFIG_CATEGORY category) {
|
||||
switch (category) {
|
||||
case X_CONFIG_CATEGORY::XCONFIG_STATIC_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.static_settings);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_STATISTIC_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.statistic);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_SECURED_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.secured);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_USER_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.user);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_XNET_MACHINE_ACCOUNT_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.xnet_machine_account);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_XNET_PARAMETERS_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.xnet_parameters);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_MEDIA_CENTER_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.media_center);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_CONSOLE_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.console);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_DVD_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.dvd);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_IPTV_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.iptv);
|
||||
case X_CONFIG_CATEGORY::XCONFIG_SYSTEM_CATEGORY:
|
||||
return reinterpret_cast<uint8_t*>(&xconfig_data_.system);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t* XConfig::CategoryBase(X_CONFIG_CATEGORY category) const {
|
||||
return const_cast<XConfig*>(this)->CategoryBase(category);
|
||||
}
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
1055
src/xenia/kernel/xconfig.h
Normal file
1055
src/xenia/kernel/xconfig.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,9 @@
|
||||
#include "xenia/ui/imgui_drawer.h"
|
||||
#include "xenia/ui/presenter.h"
|
||||
|
||||
DEFINE_int32(window_size_x, 1280, "Xenia window width", "UI");
|
||||
DEFINE_int32(window_size_y, 720, "Xenia window height", "UI");
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
@@ -242,6 +245,7 @@ void Window::SetFullscreen(bool new_fullscreen) {
|
||||
if (!CanApplyState()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowDestructionReceiver destruction_receiver(this);
|
||||
ApplyNewFullscreen();
|
||||
if (destruction_receiver.IsWindowDestroyedOrStateInapplicable()) {
|
||||
@@ -499,6 +503,7 @@ void Window::OnUsbDeviceChanged(
|
||||
|
||||
bool Window::OnActualSizeUpdate(
|
||||
uint32_t new_physical_width, uint32_t new_physical_height,
|
||||
WindowResizeAction cause_action,
|
||||
WindowDestructionReceiver& destruction_receiver) {
|
||||
if (actual_physical_width_ == new_physical_width &&
|
||||
actual_physical_height_ == new_physical_height) {
|
||||
@@ -508,6 +513,13 @@ bool Window::OnActualSizeUpdate(
|
||||
actual_physical_height_ = new_physical_height;
|
||||
// The listeners may reference the presenter, update the presenter first.
|
||||
if (presenter_surface_) {
|
||||
// Update variable only if window isn't in fullscreen mode.
|
||||
if (!fullscreen_ && cause_action == WindowResizeAction::kManual) {
|
||||
// Write new window size only if we know that window is present.
|
||||
OVERRIDE_int32(window_size_x, SizeToLogical(new_physical_width));
|
||||
OVERRIDE_int32(window_size_y, SizeToLogical(new_physical_height));
|
||||
}
|
||||
|
||||
presenter_->OnSurfaceResizeFromUIThread();
|
||||
}
|
||||
UISetupEvent e(this);
|
||||
|
||||
@@ -152,6 +152,12 @@ class Window {
|
||||
kHidden,
|
||||
};
|
||||
|
||||
enum class WindowResizeAction {
|
||||
kManual,
|
||||
kAutoMaximize,
|
||||
kAutoMinimize,
|
||||
};
|
||||
|
||||
static std::unique_ptr<Window> Create(WindowedAppContext& app_context,
|
||||
const std::string_view title,
|
||||
uint32_t desired_logical_width,
|
||||
@@ -572,6 +578,7 @@ class Window {
|
||||
// explicitly.
|
||||
bool OnActualSizeUpdate(uint32_t new_physical_width,
|
||||
uint32_t new_physical_height,
|
||||
WindowResizeAction cause_action,
|
||||
WindowDestructionReceiver& destruction_receiver);
|
||||
void OnDesiredFullscreenUpdate(bool new_fullscreen) {
|
||||
fullscreen_ = new_fullscreen;
|
||||
|
||||
@@ -124,7 +124,7 @@ bool GTKWindow::OpenImpl() {
|
||||
gtk_widget_get_allocation(drawing_area_, &drawing_area_allocation);
|
||||
OnActualSizeUpdate(uint32_t(drawing_area_allocation.width),
|
||||
uint32_t(drawing_area_allocation.height),
|
||||
destruction_receiver);
|
||||
WindowResizeAction::kManual, destruction_receiver);
|
||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||
return true;
|
||||
}
|
||||
@@ -311,7 +311,7 @@ void GTKWindow::HandleSizeUpdate(
|
||||
gtk_widget_get_allocation(drawing_area_, &drawing_area_allocation);
|
||||
OnActualSizeUpdate(uint32_t(drawing_area_allocation.width),
|
||||
uint32_t(drawing_area_allocation.height),
|
||||
destruction_receiver);
|
||||
WindowResizeAction::kManual, destruction_receiver);
|
||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ bool Win32Window::OpenImpl() {
|
||||
if (GetClientRect(hwnd_, &shown_client_rect)) {
|
||||
OnActualSizeUpdate(uint32_t(shown_client_rect.right),
|
||||
uint32_t(shown_client_rect.bottom),
|
||||
destruction_receiver);
|
||||
WindowResizeAction::kManual, destruction_receiver);
|
||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||
return true;
|
||||
}
|
||||
@@ -722,7 +722,7 @@ void Win32Window::ApplyFullscreenEntry(
|
||||
}
|
||||
|
||||
void Win32Window::HandleSizeUpdate(
|
||||
WindowDestructionReceiver& destruction_receiver) {
|
||||
WindowDestructionReceiver& destruction_receiver, DWORD cause_action) {
|
||||
if (!hwnd_) {
|
||||
// Batched size update ended when the window has already been closed, for
|
||||
// instance.
|
||||
@@ -767,7 +767,10 @@ void Win32Window::HandleSizeUpdate(
|
||||
RECT client_rect;
|
||||
if (GetClientRect(hwnd_, &client_rect)) {
|
||||
OnActualSizeUpdate(uint32_t(client_rect.right),
|
||||
uint32_t(client_rect.bottom), destruction_receiver);
|
||||
uint32_t(client_rect.bottom),
|
||||
cause_action == 0 ? WindowResizeAction::kManual
|
||||
: WindowResizeAction::kAutoMaximize,
|
||||
destruction_receiver);
|
||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||
return;
|
||||
}
|
||||
@@ -792,7 +795,7 @@ void Win32Window::EndBatchedSizeUpdate(
|
||||
// handle the deferred messages twice.
|
||||
if (batched_size_update_contained_wm_size_) {
|
||||
batched_size_update_contained_wm_size_ = false;
|
||||
HandleSizeUpdate(destruction_receiver);
|
||||
HandleSizeUpdate(destruction_receiver, 0);
|
||||
if (destruction_receiver.IsWindowDestroyed()) {
|
||||
return;
|
||||
}
|
||||
@@ -1064,7 +1067,7 @@ LRESULT Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
batched_size_update_contained_wm_size_ = true;
|
||||
} else {
|
||||
WindowDestructionReceiver destruction_receiver(this);
|
||||
HandleSizeUpdate(destruction_receiver);
|
||||
HandleSizeUpdate(destruction_receiver, wParam);
|
||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@ class Win32Window : public Window {
|
||||
|
||||
void ApplyFullscreenEntry(WindowDestructionReceiver& destruction_receiver);
|
||||
|
||||
void HandleSizeUpdate(WindowDestructionReceiver& destruction_receiver);
|
||||
void HandleSizeUpdate(WindowDestructionReceiver& destruction_receiver,
|
||||
DWORD cause_action);
|
||||
// For updating multiple factors that may influence the window size at once,
|
||||
// without handling WM_SIZE multiple times (that may not only result in wasted
|
||||
// handling, but also in the state potentially changed to an inconsistent one
|
||||
|
||||
Reference in New Issue
Block a user