From 3e89d53854b656b48f598e82eaf5eaa363088530 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Tue, 16 Sep 2025 18:09:31 +0900 Subject: [PATCH 1/4] Fix menu hotkeys in Linux UI --- src/xenia/ui/window_gtk.cc | 47 +++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/xenia/ui/window_gtk.cc b/src/xenia/ui/window_gtk.cc index 3216f9dc1..0517705d5 100644 --- a/src/xenia/ui/window_gtk.cc +++ b/src/xenia/ui/window_gtk.cc @@ -484,6 +484,31 @@ VirtualKey GTKWindow::TranslateVirtualKey(guint keyval) { return VirtualKey::kSpace; case GDK_KEY_Caps_Lock: return VirtualKey::kCapital; + case GDK_KEY_F1: + return VirtualKey::kF1; + case GDK_KEY_F3: + return VirtualKey::kF3; + case GDK_KEY_F4: + return VirtualKey::kF4; + case GDK_KEY_F5: + return VirtualKey::kF5; + case GDK_KEY_F6: + return VirtualKey::kF6; + case GDK_KEY_F11: + return VirtualKey::kF11; + case GDK_KEY_F12: + return VirtualKey::kF12; + case GDK_KEY_KP_Multiply: + return VirtualKey::kMultiply; + case GDK_KEY_KP_Add: + return VirtualKey::kAdd; + case GDK_KEY_KP_Subtract: + return VirtualKey::kSubtract; + case GDK_KEY_KP_Divide: + return VirtualKey::kDivide; + case GDK_KEY_Pause: + case GDK_KEY_Break: + return VirtualKey::kPause; default: XELOGW("Unhandled key code: {}", keyval); return VirtualKey(keyval); @@ -770,11 +795,27 @@ GTKMenuItem::GTKMenuItem(Type type, const std::string& text, menu_ = gtk_separator_menu_item_new(); break; case MenuItem::Type::kString: - auto full_name = text; if (!hotkey.empty()) { - full_name += "\t" + hotkey; + // Create a box to hold the label and the accelerator + GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + + // Create the main label with mnemonic + GtkWidget* label_widget = gtk_label_new_with_mnemonic(gtk_label); + gtk_label_set_xalign(GTK_LABEL(label_widget), 0.0); + gtk_box_pack_start(GTK_BOX(box), label_widget, FALSE, FALSE, 0); + + // Create the accelerator label (right-aligned) + GtkWidget* accel_label = gtk_label_new(hotkey.c_str()); + gtk_widget_set_margin_start(accel_label, 20); + gtk_box_pack_end(GTK_BOX(box), accel_label, FALSE, FALSE, 0); + + // Create menu item and add the box + menu_ = gtk_menu_item_new(); + gtk_container_add(GTK_CONTAINER(menu_), box); + gtk_widget_show_all(box); + } else { + menu_ = gtk_menu_item_new_with_mnemonic(gtk_label); } - menu_ = gtk_menu_item_new_with_mnemonic(gtk_label); break; } if (menu_) { From 3e6a74be131c1904c7bb543a4f5170a36cba684e Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Fri, 29 Aug 2025 00:18:50 +0900 Subject: [PATCH 2/4] Ensure runtime directories are created in storage_root() At the moment they end up wherever the command is run from on linux or exe directory on Windows, which ignores the "portable" install mechanism --- src/xenia/app/xenia_main.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index b112cd22f..d6662e0b9 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -572,7 +572,7 @@ void EmulatorApp::EmulatorThread() { if (cvars::mount_scratch) { auto scratch_device = std::make_unique( - "\\SCRATCH", "scratch", false); + "\\SCRATCH", emulator_->storage_root() / "scratch", false); if (!scratch_device->Initialize()) { XELOGE("Unable to scan scratch path"); } else { @@ -585,8 +585,8 @@ void EmulatorApp::EmulatorThread() { } if (cvars::mount_cache) { - auto cache0_device = - std::make_unique("\\CACHE0", "cache0", false); + auto cache0_device = std::make_unique( + "\\CACHE0", emulator_->storage_root() / "cache0", false); if (!cache0_device->Initialize()) { XELOGE("Unable to scan cache0 path"); } else { @@ -597,8 +597,8 @@ void EmulatorApp::EmulatorThread() { } } - auto cache1_device = - std::make_unique("\\CACHE1", "cache1", false); + auto cache1_device = std::make_unique( + "\\CACHE1", emulator_->storage_root() / "cache1", false); if (!cache1_device->Initialize()) { XELOGE("Unable to scan cache1 path"); } else { @@ -613,8 +613,8 @@ void EmulatorApp::EmulatorThread() { // NOTE: this must be registered _after_ the cache0/cache1 devices, due to // substring/start_with logic inside VirtualFileSystem::ResolvePath, else // accesses to those devices will go here instead - auto cache_device = - std::make_unique("\\CACHE", "cache", false); + auto cache_device = std::make_unique( + "\\CACHE", emulator_->storage_root() / "cache", false); if (!cache_device->Initialize()) { XELOGE("Unable to scan cache path"); } else { From fdbf22502daaf9e680b661989aa1aaefc2ac3bd1 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Wed, 23 Jul 2025 00:18:58 +0100 Subject: [PATCH 3/4] [XAM] Added util functions to check gamer picture type --- src/xenia/kernel/title_id_utils.h | 31 +++++++++++++++++++++++++++ src/xenia/kernel/xam/user_settings.cc | 2 +- src/xenia/kernel/xam/xam_user.cc | 10 +++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/xenia/kernel/title_id_utils.h b/src/xenia/kernel/title_id_utils.h index 55930a761..42a080300 100644 --- a/src/xenia/kernel/title_id_utils.h +++ b/src/xenia/kernel/title_id_utils.h @@ -106,6 +106,37 @@ inline constexpr bool IsOriginalXboxTitle(const uint32_t title_id) { static_assert(IsOriginalXboxTitle(0x41430006)); // OG-Xbox Game static_assert(!IsOriginalXboxTitle(0x4D5308BC)); // 360 Game +inline constexpr bool IsGamerPictureAvatar(const uint32_t title_id) { + if (title_id == 0xFFFE0854 || (title_id & 0xFFFF0000) == 0x20000 || + (title_id & 0xFFFF0000) == 0x10000) { + return true; + } + + return false; +} + +inline constexpr bool IsGamerPictureCustom(const uint32_t title_id) { + if (title_id == 0xFFFE0700 || (title_id & 0xFFFF0000) == 0) { + return true; + } + + return false; +} + +inline constexpr bool IsGamerPictureFromDash(const uint32_t title_id) { + return title_id == 0xFFFE07D1; +} + +inline constexpr bool IsGamerPictureKeySet(const uint32_t title_id) { + return title_id != 0; +} + +static_assert(IsGamerPictureAvatar(0xFFFE0854)); // Avatar Gamer Picture +static_assert(IsGamerPictureCustom(0xFFFE0700)); // Custom Gamer Picture +static_assert( + IsGamerPictureFromDash(0xFFFE07D1)); // Default or OS Gamer Picture? +static_assert(!IsGamerPictureKeySet(0)); // No Gamer Picture Key + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/user_settings.cc b/src/xenia/kernel/xam/user_settings.cc index 812227cea..e7d2e87de 100644 --- a/src/xenia/kernel/xam/user_settings.cc +++ b/src/xenia/kernel/xam/user_settings.cc @@ -25,7 +25,7 @@ const static std::array default_setting_values = { X_XAMACCOUNTINFO::AccountSubscriptionTier::kSubscriptionTierGold), UserSetting( UserSettingId::XPROFILE_GAMERCARD_PICTURE_KEY, - xe::string_util::read_u16string_and_swap(u"gamercard_picture_key"))}; + xe::string_util::read_u16string_and_swap(u"FFFE07D10002000200010002"))}; UserSetting::UserSetting(const UserSetting& setting) : UserData(setting) { setting_id_ = setting.setting_id_; diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 58426b490..a5ef9cbdc 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -788,6 +788,16 @@ dword_result_t XamParseGamerTileKey_entry(pointer_t key_ptr, string_util::from_string(small_tile_id, true); } + bool is_from_dash = false; + bool is_avatar = false; + bool is_custom = false; + + if (title_id_ptr) { + is_from_dash = IsGamerPictureFromDash(*title_id_ptr); + is_avatar = IsGamerPictureAvatar(*title_id_ptr); + is_custom = IsGamerPictureCustom(*title_id_ptr); + } + return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamParseGamerTileKey, kUserProfiles, kImplemented); From dd15565bee0474026c63f6c971ccbc01d4d88bf7 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Wed, 6 Aug 2025 19:15:09 +0100 Subject: [PATCH 4/4] [BUILD] Fixed parsing environment variables This fixes the git command: git rebase --exec "py xenia-build.py setup" HEAD~1 --- xenia-build.py | 57 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/xenia-build.py b/xenia-build.py index e364686bc..538c87310 100755 --- a/xenia-build.py +++ b/xenia-build.py @@ -49,28 +49,41 @@ def import_subprocess_environment(args): popen = subprocess.Popen( args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) variables, _ = popen.communicate() - envvars_to_save = ( - "devenvdir", - "include", - "lib", - "libpath", - "path", - "pathext", - "systemroot", - "temp", - "tmp", - "vcinstalldir", - "windowssdkdir", - ) - for line in variables.splitlines(): - for envvar in envvars_to_save: - if f"{envvar}=" in line.lower(): - var, setting = line.split("=", 1) - if envvar == "path": - setting = f"{os.path.dirname(sys.executable)}{os.pathsep}{setting}" - os.environ[var.upper()] = setting - break + envvars_to_save = ( + "DEVENVDIR", + "INCLUDE", + "LIB", + "LIBPATH", + "PATH", + "PATHEXT", + "SYSTEMROOT", + "TEMP", + "TMP", + "VCINSTALLDIR", + "WindowsSdkDir", + "PROGRAMFILES", + "ProgramFiles(x86)", + "VULKAN_SDK" + "CC", + "CXX", + ) + + # Extract and parse environment variables from stdout + for line in variables.splitlines(): + if line.find("=") != -1: + for envvar in envvars_to_save: + var, setting = line.split("=", 1) + + var = var.upper() + envvar = envvar.upper() + + if envvar == var: + if envvar == "PATH": + setting = f"{os.path.dirname(sys.executable)}{os.pathsep}{setting}" + + os.environ[var] = setting + break VSVERSION_MINIMUM = 2022 def import_vs_environment(): @@ -461,7 +474,7 @@ def get_clang_format_binary(): if int(clang_format_out.split("version ")[1].split(".")[0]) == int(clang_format_version_req): print(clang_format_out) return binary - print(f"ERROR: clang-format {clang_format_version_req} is not on PATH") + print(f"{bcolors.FAIL}ERROR: clang-format {clang_format_version_req} is not on PATH{bcolors.ENDC}") sys.exit(1)