Compare commits

...

24 Commits

Author SHA1 Message Date
David Griswold
01dc2bb776 android: Add Display Listener methods for smoother secondary display updates 2025-10-03 18:05:22 +01:00
OpenSauce04
4ac3cab012 externals: Updated fmt to 12.0.0
This fixes a build failure with Clang 21
2025-10-03 16:28:27 +01:00
huesos_96
897447e9bd Android: Dual screen fixes for Handhelds that have 2 screens like Ayaneo Pocket DS (#1341)
* Prevent SecondaryDisplay from stealing focus

The SecondaryDisplay Activity was stealing focus from the main
Activity when it was launched.

Set the `FLAG_NOT_FOCUSABLE` and `FLAG_NOT_TOUCH_MODAL` window flags
to prevent the SecondaryDisplay from gaining focus.

* Implement touch controls for secondary display

This commit introduces touch input handling for the secondary display.

The following changes were made:
- Added `onSecondaryTouchEvent` and `onSecondaryTouchMoved` to `NativeLibrary.kt` and `native.cpp` to process touch events on the secondary display.
- Implemented `onTouchListener` in `SecondaryDisplay.kt` to capture touch events and forward them to the native layer.
- Handles `ACTION_DOWN`, `ACTION_POINTER_DOWN`, `ACTION_MOVE`, `ACTION_UP`, `ACTION_POINTER_UP`, and `ACTION_CANCEL` motion events.
- Tracks the active pointer to ensure correct touch event handling.

* Refactor display logic for multi-display support

This commit introduces a `DisplayHelper` class to centralize display-related logic, particularly for handling scenarios where the application might be launched on an external display.

Key changes:
- Added `DisplayHelper.kt` to manage internal and external display identification based on launch conditions.
- `MainActivity` and `EmulationActivity` now use `DisplayHelper.checkLaunchDisplay()` to determine the initial display.
- `SecondaryDisplay` now uses `DisplayHelper.getExternalDisplay()` to correctly identify the target display for the secondary presentation.
- `InputOverlay` now queries `DisplayHelper.isBottomOnPrimary()` to determine if touch input should be processed for the primary display based on the current screen layout.
- `SecondaryDisplay` now queries `DisplayHelper.isBottomOnSecondary()` to conditionally pass touch events to the native layer based on which screen (primary or secondary) is currently displaying the 3DS bottom screen.

These changes ensure that the application behaves correctly when launched on either the internal or an external display, and that touch input is routed appropriately based on the user's chosen screen layout for the dual screens.

* Removed primary-screen checks so the input overlay always forwards touch events, ensuring all touches reach the native handler even when multiple displays are active

* Remove DisplayHelper class and adjust external display logic

* Formatting adjustments

---------

Co-authored-by: DavidRGriswold <novachild@gmail.com>
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
2025-10-03 14:46:05 +01:00
OpenSauce04
724576cc61 ci: Update all macOS runners to macOS 15 Sequoia 2025-10-03 14:18:27 +01:00
OpenSauce04
3e1b86548a cmake: Remove SYSTEM from target_link_libraries 2025-09-16 16:06:12 +01:00
OpenSauce04
246e06d1a4 vk_pipeline_cache: Fix directory creation failure if shaders/vulkan/ is missing 2025-09-13 01:20:32 +01:00
OpenSauce04
a607e3dd22 tools: Added Github cache purge script 2025-09-13 01:20:32 +01:00
OpenSauce04
a65114eabf Updated compatibility list 2025-09-05 22:22:32 +01:00
OpenSauce04
6ac0733002 tools: Updated guidance regarding translation updates 2025-09-05 21:56:32 +01:00
David Griswold
8519e92eae android: Re-fixed game termination bug (#1357)
* EmulationActivity and EmulationFragment clear only their own hooks

* EmulationLifecycleUtil: Rename `remove()` to `removeHook()`

* EmulationLifecycleUtil: Removed unused function `clear()`

* Corrected somewhat incorrect usage of the word "hook"

* Define `onShutdown` and `onPause` hook functions in constructors

* Formatting nitpicks

* Updated license header

* Re-added log messages for attempting to add duplicate hooks

---------

Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
2025-09-05 21:40:05 +01:00
OpenSauce04
7f2ac35870 Revert "Fix android termination bug (#1354)"
This reverts commit 70f9379eefc84b7651e3aababcce33987e073ed0.
2025-09-05 21:40:05 +01:00
OpenSauce04
1e2dd5ea78 SecondaryDisplay.kt: Remove redundant SurfaceTexture, preventing log spam 2025-09-05 21:40:05 +01:00
David Griswold
beba099fed Fix android termination bug (#1354)
* move hook additions to onCreateView

* Updated license header

* Formatting nitpick

* Added prefix to log messages

---------

Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
2025-09-04 22:59:51 +01:00
OpenSauce04
c888c40b3e macos: Set UIDesignRequiresCompatibility to true 2025-09-03 23:02:34 +01:00
OpenSauce04
57995cd89c android: Bump Vulkan Validation Layers to SDK 1.4.313.0 2025-09-03 22:31:26 +01:00
DavidRGriswold
29a77b342b android: Prevent crash when editing a slider option with an out of bounds value
Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
2025-09-03 13:18:43 +01:00
OpenSauce04
3ef5bc0bfe macos: Patch QMetalLayer.setNeedsDisplayInRect at runtime to avoid freezing on recent Qt 2025-09-03 03:16:00 +01:00
OpenSauce04
d94657a44d cmake: On Windows, download MSVC 2022 Qt versions instead of MSVC 2019 2025-09-03 03:16:00 +01:00
OpenSauce04
ee58988897 cmake: Bump downloaded Qt version to 6.9.2
Also bumps aqtinstall to 3.3.0
2025-09-03 03:16:00 +01:00
OpenSauce04
ec7f00c9a4 cmake: Added check for minimum AppleClang version 2025-09-02 14:06:53 +01:00
OpenSauce04
164b9329c7 cmake: Corrected widespread incorrect usage of the SYSTEM property 2025-09-01 00:43:01 +01:00
OpenSauce04
2292f3ab1b Updated translations via Transifex 2025-08-20 13:57:05 +01:00
PabloMK7
3ab6a304cd am: fix save data being deleted on CIA install failure (#1319) 2025-08-20 13:51:06 +01:00
OpenSauce04
2e3d926dd5 Updated language translations via Transifex 2025-08-15 17:47:35 +01:00
33 changed files with 389 additions and 123 deletions

View File

@ -62,7 +62,7 @@ jobs:
name: ${{ env.OS }}-${{ env.TARGET }} name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/ path: artifacts/
macos: macos:
runs-on: ${{ (matrix.target == 'x86_64' && 'macos-13') || 'macos-14' }} runs-on: ${{ (matrix.target == 'x86_64' && 'macos-15-intel') || 'macos-15' }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -103,7 +103,7 @@ jobs:
name: ${{ env.OS }}-${{ env.TARGET }} name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/ path: artifacts/
macos-universal: macos-universal:
runs-on: macos-14 runs-on: macos-15
needs: macos needs: macos
env: env:
OS: macos OS: macos

View File

@ -48,6 +48,15 @@ if (APPLE)
else() else()
# Minimum macOS 13 # Minimum macOS 13
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.4") set(CMAKE_OSX_DEPLOYMENT_TARGET "13.4")
# Catch compiler issue on AppleClang versions below 15.0
# TODO: Remove this check when we drop macOS 13 Ventura
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0)
message(FATAL_ERROR "AppleClang 15.0 or later is required due to a compiler bug in earlier versions.\n"
"Current version: ${CMAKE_CXX_COMPILER_VERSION}\n"
"After updating, delete 'CMakeCache.txt' in the build directory.")
endif()
endif() endif()
endif() endif()
@ -299,7 +308,7 @@ find_package(Threads REQUIRED)
if (ENABLE_QT) if (ENABLE_QT)
if (NOT USE_SYSTEM_QT) if (NOT USE_SYSTEM_QT)
download_qt(6.7.2) download_qt(6.9.2)
endif() endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent) find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)

View File

@ -20,9 +20,9 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
set(arch_path "mingw_64") set(arch_path "mingw_64")
elseif (MSVC) elseif (MSVC)
if ("arm64" IN_LIST ARCHITECTURE) if ("arm64" IN_LIST ARCHITECTURE)
set(arch_path "msvc2019_arm64") set(arch_path "msvc2022_arm64")
elseif ("x86_64" IN_LIST ARCHITECTURE) elseif ("x86_64" IN_LIST ARCHITECTURE)
set(arch_path "msvc2019_64") set(arch_path "msvc2022_64")
else() else()
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.") message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
endif() endif()
@ -30,12 +30,13 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
# In case we're cross-compiling, prepare to also fetch the correct host Qt tools. # In case we're cross-compiling, prepare to also fetch the correct host Qt tools.
if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
set(host_arch_path "msvc2019_64") set(host_arch_path "msvc2022_64")
elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64") elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64")
# TODO: msvc2019_arm64 doesn't include some of the required tools for some reason, # TODO: msvc2019_arm64 doesn't include some of the required tools for some reason,
# TODO: so until it does, just use msvc2019_64 under x86_64 emulation. # TODO: so until it does, just use msvc2019_64 under x86_64 emulation.
# TODO: ^ Is this still true with msvc2022?
# set(host_arch_path "msvc2019_arm64") # set(host_arch_path "msvc2019_arm64")
set(host_arch_path "msvc2019_64") set(host_arch_path "msvc2022_64")
endif() endif()
set(host_arch "win64_${host_arch_path}") set(host_arch "win64_${host_arch_path}")
else() else()
@ -105,7 +106,7 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
if (NOT EXISTS "${prefix}") if (NOT EXISTS "${prefix}")
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}") message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.1.18") set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0")
if (WIN32) if (WIN32)
set(aqt_path "${base_path}/aqt.exe") set(aqt_path "${base_path}/aqt.exe")
if (NOT EXISTS "${aqt_path}") if (NOT EXISTS "${aqt_path}")

View File

@ -75,6 +75,9 @@
<true/> <true/>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
<string>True</string> <string>True</string>
<key>UIDesignRequiresCompatibility</key>
<true/> <!-- Remove when Qt Liquid Glass issues are fixed upstream:
https://bugreports.qt.io/browse/QTBUG-138942 -->
<key>UIFileSharingEnabled</key> <key>UIFileSharingEnabled</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

@ -1 +1 @@
Subproject commit 4f39041699412873d0afcec89a9313148a192647 Subproject commit a36decbe43d0e5a570ac3d3ba9a0b226dc832a17

View File

@ -27,7 +27,7 @@
<message> <message>
<location filename="../../src/citra_qt/aboutdialog.ui" line="30"/> <location filename="../../src/citra_qt/aboutdialog.ui" line="30"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/default/256x256/azahar.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/default/256x256/azahar.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"/> <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;img src=&quot;:/icons/default/256x256/azahar.png&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/aboutdialog.ui" line="60"/> <location filename="../../src/citra_qt/aboutdialog.ui" line="60"/>
@ -725,7 +725,7 @@ Desitja ignorar l&apos;error i continuar?</translation>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_debug.ui" line="107"/> <location filename="../../src/citra_qt/configuration/configure_debug.ui" line="107"/>
<source>Show log output in console</source> <source>Show log output in console</source>
<translation type="unfinished"/> <translation>Mostrar l&apos;eixida del registre en la consola</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_debug.ui" line="114"/> <location filename="../../src/citra_qt/configuration/configure_debug.ui" line="114"/>
@ -2275,7 +2275,7 @@ Desitja ignorar l&apos;error i continuar?</translation>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_motion_touch.cpp" line="102"/> <location filename="../../src/citra_qt/configuration/configure_motion_touch.cpp" line="102"/>
<source>&lt;a href=&apos;https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source> <source>&lt;a href=&apos;https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
<translation type="unfinished"/> <translation>&lt;a href=&apos;https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Més Informació&lt;/span&gt;&lt;/a&gt;</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_motion_touch.cpp" line="209"/> <location filename="../../src/citra_qt/configuration/configure_motion_touch.cpp" line="209"/>
@ -2494,12 +2494,12 @@ Desitja ignorar l&apos;error i continuar?</translation>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_storage.ui" line="187"/> <location filename="../../src/citra_qt/configuration/configure_storage.ui" line="187"/>
<source>Compress installed CIA content</source> <source>Compress installed CIA content</source>
<translation type="unfinished"/> <translation>Comprimir el contingut de CIAs instal·lats</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_storage.ui" line="190"/> <location filename="../../src/citra_qt/configuration/configure_storage.ui" line="190"/>
<source>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</source> <source>Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.</source>
<translation type="unfinished"/> <translation>Comprimix el contingut de fitxers CIA quan són instal·lats a la SD emulada. Només afecta contingut CIA instal·lat amb esta opció activada.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_storage.cpp" line="26"/> <location filename="../../src/citra_qt/configuration/configure_storage.cpp" line="26"/>
@ -4431,7 +4431,7 @@ Vols reinstal·lar els arxius de totes maneres?</translation>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2250"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2250"/>
<source>3DS Installation File (*.cia *.zcia)</source> <source>3DS Installation File (*.cia *.zcia)</source>
<translation type="unfinished"/> <translation>Fitxers d&apos;Instalació de 3DS (*.cia *.zcia)</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2250"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2250"/>
@ -4510,24 +4510,24 @@ Vols reinstal·lar els arxius de totes maneres?</translation>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3107"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3107"/>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3113"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3113"/>
<source>Error compressing file</source> <source>Error compressing file</source>
<translation type="unfinished"/> <translation>Error al comprimir el fitxer</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2339"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2339"/>
<source>File compress operation failed, check log for details.</source> <source>File compress operation failed, check log for details.</source>
<translation type="unfinished"/> <translation>Operació de compressió fallida, mira el registre per a més detalls.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2341"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2341"/>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3181"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3181"/>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3188"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3188"/>
<source>Error decompressing file</source> <source>Error decompressing file</source>
<translation type="unfinished"/> <translation>Error de descompressió del fitxer</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2342"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2342"/>
<source>File decompress operation failed, check log for details.</source> <source>File decompress operation failed, check log for details.</source>
<translation type="unfinished"/> <translation>Operació de descompressió fallida, mira el registre per a més detalls.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2364"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2364"/>
@ -4663,62 +4663,62 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda.</translation>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3063"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3063"/>
<source>Load 3DS ROM File</source> <source>Load 3DS ROM File</source>
<translation type="unfinished"/> <translation>Carregar ROM de 3DS</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3064"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3064"/>
<source>3DS ROM Files (*.cia *cci *3dsx *cxi)</source> <source>3DS ROM Files (*.cia *cci *3dsx *cxi)</source>
<translation type="unfinished"/> <translation>Fitxers ROM 3DS (*.cia *cci *3dsx *cxi)</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3108"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3108"/>
<source>The selected file is not a compatible 3DS ROM format. Make sure you have chosen the right file, and that it is not encrypted.</source> <source>The selected file is not a compatible 3DS ROM format. Make sure you have chosen the right file, and that it is not encrypted.</source>
<translation type="unfinished"/> <translation>El fitxer seleccionat no és un ROM de 3DS compatible. Assegura&apos;t que has triat el fitxer correcte i que no estiga xifrat.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3114"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3114"/>
<source>The selected file is already compressed.</source> <source>The selected file is already compressed.</source>
<translation type="unfinished"/> <translation>El fitxer seleccionat ja està comprimit.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3119"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3119"/>
<source>3DS Compressed ROM File (*.%1)</source> <source>3DS Compressed ROM File (*.%1)</source>
<translation type="unfinished"/> <translation>Fitxer ROM 3DS comprimit (*.%1)</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3127"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3127"/>
<source>Save 3DS Compressed ROM File</source> <source>Save 3DS Compressed ROM File</source>
<translation type="unfinished"/> <translation>Desar fitxer 3DS comprimit</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3152"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3152"/>
<source>Load 3DS Compressed ROM File</source> <source>Load 3DS Compressed ROM File</source>
<translation type="unfinished"/> <translation>Carregar fitxer 3DS comprimit</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3153"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3153"/>
<source>3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi)</source> <source>3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi)</source>
<translation type="unfinished"/> <translation>Fitxer ROM 3DS comprimit (*.zcia *zcci *z3dsx *zcxi)</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3182"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3182"/>
<source>The selected file is not a compatible compressed 3DS ROM format. Make sure you have chosen the right file.</source> <source>The selected file is not a compatible compressed 3DS ROM format. Make sure you have chosen the right file.</source>
<translation type="unfinished"/> <translation>El fitxer seleccionat no és un format de ROM 3DS comprimit compatible. Assegura&apos;t d&apos;haver triat l&apos;arxiu correcte.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3189"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3189"/>
<source>The selected file is already decompressed.</source> <source>The selected file is already decompressed.</source>
<translation type="unfinished"/> <translation>El fitxer seleccionat ja està descomprimit.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3194"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3194"/>
<source>3DS ROM File (*.%1)</source> <source>3DS ROM File (*.%1)</source>
<translation type="unfinished"/> <translation>Fitxer ROM 3DS (*.%1)</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3202"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3202"/>
<source>Save 3DS ROM File</source> <source>Save 3DS ROM File</source>
<translation type="unfinished"/> <translation>Desar fitxer ROM 3DS</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3227"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3227"/>
@ -4818,7 +4818,7 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda.</translation>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3431"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3431"/>
<source>Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms)</source> <source>Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms)</source>
<translation type="unfinished"/> <translation>Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms)</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3440"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3440"/>
@ -4839,7 +4839,7 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda.</translation>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3600"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3600"/>
<source>%1 is missing. Please &lt;a href=&apos;https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/&apos;&gt;dump your system archives&lt;/a&gt;.&lt;br/&gt;Continuing emulation may result in crashes and bugs.</source> <source>%1 is missing. Please &lt;a href=&apos;https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/&apos;&gt;dump your system archives&lt;/a&gt;.&lt;br/&gt;Continuing emulation may result in crashes and bugs.</source>
<translation type="unfinished"/> <translation>Falta %1 . Per favor,&lt;a href=&apos;https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/&apos;&gt;bolca els teus arxius de sistema&lt;/a&gt;.&lt;br/&gt;Continuar l&apos;emulació pot resultar en penges i errors.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3608"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3608"/>
@ -4869,7 +4869,7 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda.</translation>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3627"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3627"/>
<source>A fatal error occurred. &lt;a href=&apos;https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Check the log&lt;/a&gt; for details.&lt;br/&gt;Continuing emulation may result in crashes and bugs.</source> <source>A fatal error occurred. &lt;a href=&apos;https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Check the log&lt;/a&gt; for details.&lt;br/&gt;Continuing emulation may result in crashes and bugs.</source>
<translation type="unfinished"/> <translation>Error fatal.&lt;a href=&apos;https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296&apos;&gt;Mira el log&lt;/a&gt;per a més detalls.&lt;br/&gt;Continuar l&apos;emulació pot resultar en penges i errors.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3632"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3632"/>
@ -6387,12 +6387,12 @@ Missatge de depuració:</translation>
<message> <message>
<location filename="../../src/citra_qt/main.ui" line="466"/> <location filename="../../src/citra_qt/main.ui" line="466"/>
<source>Compress ROM File...</source> <source>Compress ROM File...</source>
<translation type="unfinished"/> <translation>Comprimir fitxer ROM...</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/main.ui" line="471"/> <location filename="../../src/citra_qt/main.ui" line="471"/>
<source>Decompress ROM File...</source> <source>Decompress ROM File...</source>
<translation type="unfinished"/> <translation>Descomprimir fitxer ROM...</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/main.ui" line="479"/> <location filename="../../src/citra_qt/main.ui" line="479"/>

View File

@ -4517,7 +4517,7 @@ Reinstall the files anyway?</source>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2339"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2339"/>
<source>File compress operation failed, check log for details.</source> <source>File compress operation failed, check log for details.</source>
<translation>Operación de comprensión fallida, mira el registro para más detalles.</translation> <translation>Operación de compresión fallida, mira el registro para más detalles.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2341"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2341"/>
@ -4529,7 +4529,7 @@ Reinstall the files anyway?</source>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2342"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2342"/>
<source>File decompress operation failed, check log for details.</source> <source>File decompress operation failed, check log for details.</source>
<translation>Operación de descomprensión fallida, mira el registro para más detalles.</translation> <translation>Operación de descompresión fallida, mira el registro para más detalles.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2364"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2364"/>

View File

@ -3894,7 +3894,7 @@ Drag points to change position, or double-click table cells to edit values.</sou
<message> <message>
<location filename="../../src/citra_qt/configuration/configure_web.ui" line="26"/> <location filename="../../src/citra_qt/configuration/configure_web.ui" line="26"/>
<source>Show current application in your Discord status</source> <source>Show current application in your Discord status</source>
<translation type="unfinished"></translation> <translation>Показывать текущее приложение в статусе Discord</translation>
</message> </message>
</context> </context>
<context> <context>
@ -4027,7 +4027,7 @@ Drag points to change position, or double-click table cells to edit values.</sou
<location filename="../../src/citra_qt/dumping/dumping_dialog.cpp" line="25"/> <location filename="../../src/citra_qt/dumping/dumping_dialog.cpp" line="25"/>
<location filename="../../src/citra_qt/dumping/dumping_dialog.cpp" line="85"/> <location filename="../../src/citra_qt/dumping/dumping_dialog.cpp" line="85"/>
<source>Azahar</source> <source>Azahar</source>
<translation type="unfinished">Azahar</translation> <translation>Azahar</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/dumping/dumping_dialog.cpp" line="25"/> <location filename="../../src/citra_qt/dumping/dumping_dialog.cpp" line="25"/>
@ -4170,7 +4170,7 @@ Please check your FFmpeg installation used for compilation.</source>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="1299"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="1299"/>
<source>GBA Virtual Console is not supported by Azahar.</source> <source>GBA Virtual Console is not supported by Azahar.</source>
<translation type="unfinished"></translation> <translation>Azahar не поддерживает GBA Virtual Console.</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="1304"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="1304"/>
@ -4315,7 +4315,7 @@ Please check your FFmpeg installation used for compilation.</source>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3682"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3682"/>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3775"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3775"/>
<source>Azahar</source> <source>Azahar</source>
<translation type="unfinished">Azahar</translation> <translation>Azahar</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2066"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2066"/>
@ -4523,7 +4523,7 @@ Reinstall the files anyway?</source>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3181"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3181"/>
<location filename="../../src/citra_qt/citra_qt.cpp" line="3188"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="3188"/>
<source>Error decompressing file</source> <source>Error decompressing file</source>
<translation type="unfinished"></translation> <translation>Ошибра при разжатии файла</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/citra_qt.cpp" line="2342"/> <location filename="../../src/citra_qt/citra_qt.cpp" line="2342"/>
@ -5036,7 +5036,7 @@ Would you like to download it?</source>
<message> <message>
<location filename="../../src/citra_qt/game_list.cpp" line="366"/> <location filename="../../src/citra_qt/game_list.cpp" line="366"/>
<source>Don&apos;t show again</source> <source>Don&apos;t show again</source>
<translation type="unfinished"></translation> <translation>Не показывать снова</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/game_list.cpp" line="564"/> <location filename="../../src/citra_qt/game_list.cpp" line="564"/>
@ -7383,7 +7383,8 @@ They may have left the room.</source>
<source>Azahar has detected user data for Citra. <source>Azahar has detected user data for Citra.
</source> </source>
<translation type="unfinished"></translation> <translation>Azahar обнаружил файлы пользователя Citra.
</translation>
</message> </message>
<message> <message>
<location filename="../../src/citra_qt/user_data_migration.cpp" line="77"/> <location filename="../../src/citra_qt/user_data_migration.cpp" line="77"/>

View File

@ -1,24 +1,37 @@
# Definitions for all external bundled libraries # Definitions for all external bundled libraries
# Suppress warnings from external libraries # Suppress warnings from external libraries
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") if (MSVC)
add_compile_options(/W0) add_compile_options(/W0)
else() else()
add_compile_options(-w) add_compile_options(-w)
endif() endif()
function(target_disable_warnings target)
if (MSVC)
target_compile_options(${target} INTERFACE /W0)
else()
target_compile_options(${target} INTERFACE -w)
endif()
endfunction()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
include(DownloadExternals) include(DownloadExternals)
include(ExternalProject) include(ExternalProject)
# Boost # Boost
if (NOT USE_SYSTEM_BOOST) if (USE_SYSTEM_BOOST)
unset(BOOST_ROOT CACHE)
unset(Boost_INCLUDE_DIR CACHE)
set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "" FORCE)
else()
message(STATUS "Including vendored Boost library") message(STATUS "Including vendored Boost library")
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "") set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "") set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "") set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
add_library(boost INTERFACE) add_library(boost INTERFACE)
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR}) target_include_directories(boost INTERFACE ${Boost_INCLUDE_DIR})
target_disable_warnings(boost)
# Boost::serialization # Boost::serialization
file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp") file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
@ -33,11 +46,7 @@ if (NOT USE_SYSTEM_BOOST)
${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp
) )
target_link_libraries(boost_iostreams PUBLIC boost) target_link_libraries(boost_iostreams PUBLIC boost)
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists! # Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
else()
unset(BOOST_ROOT CACHE)
unset(Boost_INCLUDE_DIR CACHE)
set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "" FORCE)
endif() endif()
# Catch2 # Catch2
@ -73,6 +82,7 @@ endif()
# dds-ktx # dds-ktx
add_library(dds-ktx INTERFACE) add_library(dds-ktx INTERFACE)
target_include_directories(dds-ktx INTERFACE ./dds-ktx) target_include_directories(dds-ktx INTERFACE ./dds-ktx)
target_disable_warnings(dds-ktx)
# fmt and Xbyak need to be added before dynarmic # fmt and Xbyak need to be added before dynarmic
# libfmt # libfmt
@ -137,7 +147,8 @@ endif()
# MicroProfile # MicroProfile
add_library(microprofile INTERFACE) add_library(microprofile INTERFACE)
target_include_directories(microprofile SYSTEM INTERFACE ./microprofile) target_include_directories(microprofile INTERFACE ./microprofile)
target_disable_warnings(microprofile)
if (ENABLE_MICROPROFILE) if (ENABLE_MICROPROFILE)
target_compile_definitions(microprofile INTERFACE MICROPROFILE_ENABLED=1) target_compile_definitions(microprofile INTERFACE MICROPROFILE_ENABLED=1)
else() else()
@ -146,10 +157,11 @@ endif()
# Nihstro # Nihstro
add_library(nihstro-headers INTERFACE) add_library(nihstro-headers INTERFACE)
target_include_directories(nihstro-headers SYSTEM INTERFACE ./nihstro/include) target_include_directories(nihstro-headers INTERFACE ./nihstro/include)
if (MSVC) target_disable_warnings(nihstro-headers)
# TODO: For some reason MSVC still applies this warning even with /W0 for externals. if (NOT MSVC)
target_compile_options(nihstro-headers INTERFACE /wd4715) # TODO: For some reason MSYS2 still applied this warnin even with -w
target_compile_options(nihstro-headers INTERFACE -Wno-invalid-specialization)
endif() endif()
# Open Source Archives # Open Source Archives
@ -173,7 +185,8 @@ if (USE_SYSTEM_FFMPEG_HEADERS)
endif() endif()
if (NOT FOUND_FFMPEG_HEADERS) if (NOT FOUND_FFMPEG_HEADERS)
message(STATUS "Using bundled ffmpeg headers.") message(STATUS "Using bundled ffmpeg headers.")
target_include_directories(library-headers SYSTEM INTERFACE ./library-headers/ffmpeg/include) target_include_directories(library-headers INTERFACE ./library-headers/ffmpeg/include)
target_disable_warnings(library-headers)
endif() endif()
# SoundTouch # SoundTouch
@ -294,7 +307,8 @@ if (USE_SYSTEM_JSON)
# Citra uses "#include <json.hpp>" so we have to add this manually # Citra uses "#include <json.hpp>" so we have to add this manually
target_include_directories(json-headers SYSTEM INTERFACE "${NLOHMANN_PREFIX}/nlohmann") target_include_directories(json-headers SYSTEM INTERFACE "${NLOHMANN_PREFIX}/nlohmann")
else() else()
target_include_directories(json-headers SYSTEM INTERFACE ./json) target_include_directories(json-headers INTERFACE ./json)
target_disable_warnings(json-headers)
endif() endif()
# OpenSSL # OpenSSL
@ -310,7 +324,8 @@ if (NOT OPENSSL_FOUND)
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
set(OPENSSLDIR "/etc/ssl/") set(OPENSSLDIR "/etc/ssl/")
add_subdirectory(libressl EXCLUDE_FROM_ALL) add_subdirectory(libressl EXCLUDE_FROM_ALL)
target_include_directories(ssl SYSTEM INTERFACE ./libressl/include) target_include_directories(ssl INTERFACE ./libressl/include)
target_disable_warnings(ssl)
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP) target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
get_directory_property(OPENSSL_LIBRARIES get_directory_property(OPENSSL_LIBRARIES
DIRECTORY libressl DIRECTORY libressl
@ -327,17 +342,20 @@ if(USE_SYSTEM_CPP_HTTPLIB)
get_target_property(HTTP_LIBS httplib::httplib INTERFACE_LINK_LIBRARIES) get_target_property(HTTP_LIBS httplib::httplib INTERFACE_LINK_LIBRARIES)
if(HTTP_LIBS) if(HTTP_LIBS)
message(WARNING "Shared cpp-http (${HTTP_LIBS}) not supported. Falling back to bundled...") message(WARNING "Shared cpp-http (${HTTP_LIBS}) not supported. Falling back to bundled...")
target_include_directories(httplib SYSTEM INTERFACE ./httplib) target_include_directories(httplib INTERFACE ./httplib)
target_disable_warnings(httplib)
else() else()
if(CppHttp_FOUND) if(CppHttp_FOUND)
target_link_libraries(httplib INTERFACE httplib::httplib) target_link_libraries(httplib INTERFACE httplib::httplib)
else() else()
message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...") message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...")
target_include_directories(httplib SYSTEM INTERFACE ./httplib) target_include_directories(httplib INTERFACE ./httplib)
endif() target_disable_warnings(httplib)
endif()
endif() endif()
else() else()
target_include_directories(httplib SYSTEM INTERFACE ./httplib) target_include_directories(httplib INTERFACE ./httplib)
target_disable_warnings(httplib)
endif() endif()
target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT) target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES}) target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
@ -354,7 +372,8 @@ if (ENABLE_WEB_SERVICE)
target_link_libraries(cpp-jwt INTERFACE cpp-jwt::cpp-jwt) target_link_libraries(cpp-jwt INTERFACE cpp-jwt::cpp-jwt)
else() else()
add_library(cpp-jwt INTERFACE) add_library(cpp-jwt INTERFACE)
target_include_directories(cpp-jwt SYSTEM INTERFACE ./cpp-jwt/include) target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
target_disable_warnings(cpp-jwt)
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON) target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
endif() endif()
endif() endif()
@ -453,7 +472,8 @@ if (ENABLE_VULKAN)
endif() endif()
else() else()
add_library(vma INTERFACE) add_library(vma INTERFACE)
target_include_directories(vma SYSTEM INTERFACE ./vma/include) target_include_directories(vma INTERFACE ./vma/include)
target_disable_warnings(vma)
endif() endif()
# vulkan-headers # vulkan-headers
@ -465,7 +485,8 @@ if (ENABLE_VULKAN)
target_link_libraries(vulkan-headers INTERFACE Vulkan::Headers) target_link_libraries(vulkan-headers INTERFACE Vulkan::Headers)
endif() endif()
else() else()
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include) target_include_directories(vulkan-headers INTERFACE ./vulkan-headers/include)
target_disable_warnings(vulkan-headers)
endif() endif()
# adrenotools # adrenotools

2
externals/fmt vendored

@ -1 +1 @@
Subproject commit 123913715afeb8a437e6388b4473fcc4753e1c9a Subproject commit e424e3f2e607da02742f73db84873b8084fc714c

View File

@ -186,7 +186,7 @@ dependencies {
// Download Vulkan Validation Layers from the KhronosGroup GitHub. // Download Vulkan Validation Layers from the KhronosGroup GitHub.
val downloadVulkanValidationLayers = tasks.register<Download>("downloadVulkanValidationLayers") { val downloadVulkanValidationLayers = tasks.register<Download>("downloadVulkanValidationLayers") {
src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.304.1/android-binaries-1.4.304.1.zip") src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.313.0/android-binaries-1.4.313.0.zip")
dest(file("${layout.buildDirectory.get().asFile.path}/tmp/Vulkan-ValidationLayers.zip")) dest(file("${layout.buildDirectory.get().asFile.path}/tmp/Vulkan-ValidationLayers.zip"))
onlyIfModified(true) onlyIfModified(true)
} }

View File

@ -96,6 +96,24 @@ object NativeLibrary {
*/ */
external fun onTouchMoved(xAxis: Float, yAxis: Float) external fun onTouchMoved(xAxis: Float, yAxis: Float)
/**
* Handles touch events on the secondary display.
*
* @param xAxis The value of the x-axis.
* @param yAxis The value of the y-axis.
* @param pressed To identify if the touch held down or released.
* @return true if the pointer is within the touchscreen
*/
external fun onSecondaryTouchEvent(xAxis: Float, yAxis: Float, pressed: Boolean): Boolean
/**
* Handles touch movement on the secondary display.
*
* @param xAxis The value of the instantaneous x-axis.
* @param yAxis The value of the instantaneous y-axis.
*/
external fun onSecondaryTouchMoved(xAxis: Float, yAxis: Float)
external fun reloadSettings() external fun reloadSettings()
external fun getTitleId(filename: String): Long external fun getTitleId(filename: String): Long

View File

@ -60,7 +60,15 @@ class EmulationActivity : AppCompatActivity() {
private lateinit var binding: ActivityEmulationBinding private lateinit var binding: ActivityEmulationBinding
private lateinit var screenAdjustmentUtil: ScreenAdjustmentUtil private lateinit var screenAdjustmentUtil: ScreenAdjustmentUtil
private lateinit var hotkeyUtility: HotkeyUtility private lateinit var hotkeyUtility: HotkeyUtility
private lateinit var secondaryDisplay: SecondaryDisplay; private lateinit var secondaryDisplay: SecondaryDisplay
private val onShutdown = Runnable {
if (intent.getBooleanExtra("launched_from_shortcut", false)) {
finishAffinity()
} else {
this.finish()
}
}
private val emulationFragment: EmulationFragment private val emulationFragment: EmulationFragment
get() { get() {
@ -77,8 +85,8 @@ class EmulationActivity : AppCompatActivity() {
ThemeUtil.setTheme(this) ThemeUtil.setTheme(this)
settingsViewModel.settings.loadSettings() settingsViewModel.settings.loadSettings()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
secondaryDisplay = SecondaryDisplay(this); secondaryDisplay = SecondaryDisplay(this)
secondaryDisplay.updateDisplay(); secondaryDisplay.updateDisplay()
binding = ActivityEmulationBinding.inflate(layoutInflater) binding = ActivityEmulationBinding.inflate(layoutInflater)
screenAdjustmentUtil = ScreenAdjustmentUtil(this, windowManager, settingsViewModel.settings) screenAdjustmentUtil = ScreenAdjustmentUtil(this, windowManager, settingsViewModel.settings)
@ -101,13 +109,7 @@ class EmulationActivity : AppCompatActivity() {
windowManager.defaultDisplay.rotation windowManager.defaultDisplay.rotation
) )
EmulationLifecycleUtil.addShutdownHook(hook = { EmulationLifecycleUtil.addShutdownHook(onShutdown)
if (intent.getBooleanExtra("launched_from_shortcut", false)) {
finishAffinity()
} else {
this.finish()
}
})
isEmulationRunning = true isEmulationRunning = true
instance = this instance = this
@ -165,12 +167,12 @@ class EmulationActivity : AppCompatActivity() {
} }
override fun onDestroy() { override fun onDestroy() {
EmulationLifecycleUtil.clear() EmulationLifecycleUtil.removeHook(onShutdown)
NativeLibrary.playTimeManagerStop() NativeLibrary.playTimeManagerStop()
isEmulationRunning = false isEmulationRunning = false
instance = null instance = null
secondaryDisplay.releasePresentation() secondaryDisplay.releasePresentation()
secondaryDisplay.releaseVD(); secondaryDisplay.releaseVD()
super.onDestroy() super.onDestroy()
} }

View File

@ -11,29 +11,30 @@ import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay import android.hardware.display.VirtualDisplay
import android.os.Bundle import android.os.Bundle
import android.view.Display import android.view.Display
import android.view.MotionEvent
import android.view.Surface import android.view.Surface
import android.view.SurfaceHolder import android.view.SurfaceHolder
import android.view.SurfaceView import android.view.SurfaceView
import org.citra.citra_emu.NativeLibrary import android.view.WindowManager
import org.citra.citra_emu.features.settings.model.IntSetting import org.citra.citra_emu.features.settings.model.IntSetting
import org.citra.citra_emu.display.SecondaryDisplayLayout
import org.citra.citra_emu.NativeLibrary
class SecondaryDisplay(val context: Context) { class SecondaryDisplay(val context: Context) : DisplayManager.DisplayListener {
private var pres: SecondaryDisplayPresentation? = null private var pres: SecondaryDisplayPresentation? = null
private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
private val vd: VirtualDisplay private val vd: VirtualDisplay
init { init {
val st = SurfaceTexture(0)
st.setDefaultBufferSize(1920, 1080)
val vdSurface = Surface(st)
vd = displayManager.createVirtualDisplay( vd = displayManager.createVirtualDisplay(
"HiddenDisplay", "HiddenDisplay",
1920, 1920,
1080, 1080,
320, 320,
vdSurface, null,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION
) )
displayManager.registerDisplayListener(this, null)
} }
fun updateSurface() { fun updateSurface() {
@ -44,16 +45,23 @@ class SecondaryDisplay(val context: Context) {
NativeLibrary.secondarySurfaceDestroyed() NativeLibrary.secondarySurfaceDestroyed()
} }
private fun getExternalDisplay(context: Context): Display? {
val dm = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val internalId = context.display.displayId ?: Display.DEFAULT_DISPLAY
val displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION)
return displays.firstOrNull { it.displayId != internalId && it.name != "HiddenDisplay" }
}
fun updateDisplay() { fun updateDisplay() {
// decide if we are going to the external display or the internal one // decide if we are going to the external display or the internal one
var display = getCustomerDisplay() var display = getExternalDisplay(context)
if (display == null || if (display == null ||
IntSetting.SECONDARY_DISPLAY_LAYOUT.int == SecondaryDisplayLayout.NONE.int) { IntSetting.SECONDARY_DISPLAY_LAYOUT.int == SecondaryDisplayLayout.NONE.int) {
display = vd.display display = vd.display
} }
// if our presentation is already on the right display, ignore // if our presentation is already on the right display, ignore
if (pres?.display == display) return; if (pres?.display == display) return
// otherwise, make a new presentation // otherwise, make a new presentation
releasePresentation() releasePresentation()
@ -61,29 +69,41 @@ class SecondaryDisplay(val context: Context) {
pres?.show() pres?.show()
} }
private fun getCustomerDisplay(): Display? {
val displays = displayManager.displays
// code taken from MelonDS dual screen - should fix odin 2 detection bug
return displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION)
.firstOrNull { it.displayId != Display.DEFAULT_DISPLAY && it.name != "Built-in Screen" && it.name != "HiddenDisplay"}
}
fun releasePresentation() { fun releasePresentation() {
pres?.dismiss() pres?.dismiss()
pres = null pres = null
} }
fun releaseVD() { fun releaseVD() {
displayManager.unregisterDisplayListener(this)
vd.release() vd.release()
} }
override fun onDisplayAdded(displayId: Int) {
updateDisplay()
}
override fun onDisplayRemoved(displayId: Int) {
updateDisplay()
}
override fun onDisplayChanged(displayId: Int) {
updateDisplay()
}
} }
class SecondaryDisplayPresentation( class SecondaryDisplayPresentation(
context: Context, display: Display, val parent: SecondaryDisplay context: Context, display: Display, val parent: SecondaryDisplay
) : Presentation(context, display) { ) : Presentation(context, display) {
private lateinit var surfaceView: SurfaceView private lateinit var surfaceView: SurfaceView
private var touchscreenPointerId = -1
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
window?.setFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
)
// Initialize SurfaceView // Initialize SurfaceView
surfaceView = SurfaceView(context) surfaceView = SurfaceView(context)
@ -103,6 +123,42 @@ class SecondaryDisplayPresentation(
} }
}) })
this.surfaceView.setOnTouchListener { _, event ->
val pointerIndex = event.actionIndex
val pointerId = event.getPointerId(pointerIndex)
when (event.actionMasked) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
if (touchscreenPointerId == -1) {
touchscreenPointerId = pointerId
NativeLibrary.onSecondaryTouchEvent(
event.getX(pointerIndex),
event.getY(pointerIndex),
true
)
}
}
MotionEvent.ACTION_MOVE -> {
val index = event.findPointerIndex(touchscreenPointerId)
if (index != -1) {
NativeLibrary.onSecondaryTouchMoved(
event.getX(index),
event.getY(index)
)
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> {
if (pointerId == touchscreenPointerId) {
NativeLibrary.onSecondaryTouchEvent(0f, 0f, false)
touchscreenPointerId = -1
}
}
}
true
}
setContentView(surfaceView) // Set SurfaceView as content setContentView(surfaceView) // Set SurfaceView as content
} }

View File

@ -1,4 +1,4 @@
// Copyright Citra Emulator Project / Lime3DS Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
@ -10,7 +10,6 @@ import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.FloatSetting import org.citra.citra_emu.features.settings.model.FloatSetting
import org.citra.citra_emu.features.settings.model.ScaledFloatSetting import org.citra.citra_emu.features.settings.model.ScaledFloatSetting
import org.citra.citra_emu.utils.Log import org.citra.citra_emu.utils.Log
import kotlin.math.roundToInt
class SliderSetting( class SliderSetting(
setting: AbstractSetting?, setting: AbstractSetting?,
@ -27,7 +26,8 @@ class SliderSetting(
val selectedFloat: Float val selectedFloat: Float
get() { get() {
val setting = setting ?: return defaultValue!!.toFloat() val setting = setting ?: return defaultValue!!.toFloat()
return when (setting) {
val ret = when (setting) {
is AbstractIntSetting -> setting.int.toFloat() is AbstractIntSetting -> setting.int.toFloat()
is FloatSetting -> setting.float is FloatSetting -> setting.float
is ScaledFloatSetting -> setting.float is ScaledFloatSetting -> setting.float
@ -36,8 +36,8 @@ class SliderSetting(
-1f -1f
} }
} }
return ret.coerceIn(min.toFloat(), max.toFloat())
} }
/** /**
* Write a value to the backing int. If that int was previously null, * Write a value to the backing int. If that int was previously null,
* initializes a new one and returns it, so it can be added to the Hashmap. * initializes a new one and returns it, so it can be added to the Hashmap.

View File

@ -101,6 +101,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
private val emulationViewModel: EmulationViewModel by activityViewModels() private val emulationViewModel: EmulationViewModel by activityViewModels()
private val settingsViewModel: SettingsViewModel by viewModels() private val settingsViewModel: SettingsViewModel by viewModels()
private val onPause = Runnable{ togglePause() }
private val onShutdown = Runnable{ emulationState.stop() }
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
if (context is EmulationActivity) { if (context is EmulationActivity) {
@ -156,8 +159,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
emulationState = EmulationState(game.path) emulationState = EmulationState(game.path)
emulationActivity = requireActivity() as EmulationActivity emulationActivity = requireActivity() as EmulationActivity
screenAdjustmentUtil = ScreenAdjustmentUtil(requireContext(), requireActivity().windowManager, settingsViewModel.settings) screenAdjustmentUtil = ScreenAdjustmentUtil(requireContext(), requireActivity().windowManager, settingsViewModel.settings)
EmulationLifecycleUtil.addShutdownHook(hook = { emulationState.stop() }) EmulationLifecycleUtil.addPauseResumeHook(onPause)
EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() }) EmulationLifecycleUtil.addShutdownHook(onShutdown)
} }
override fun onCreateView( override fun onCreateView(
@ -507,6 +510,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
super.onDetach() super.onDetach()
} }
override fun onDestroy() {
EmulationLifecycleUtil.removeHook(onPause)
EmulationLifecycleUtil.removeHook(onShutdown)
super.onDestroy()
}
private fun setupCitraDirectoriesThenStartEmulation() { private fun setupCitraDirectoriesThenStartEmulation() {
val directoryInitializationState = DirectoryInitialization.start() val directoryInitializationState = DirectoryInitialization.start()
if (directoryInitializationState === if (directoryInitializationState ===

View File

@ -153,8 +153,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
if (isActionMove) { if (isActionMove) {
NativeLibrary.onTouchMoved(xPosition.toFloat(), yPosition.toFloat()) NativeLibrary.onTouchMoved(xPosition.toFloat(), yPosition.toFloat())
continue continue
} } else if (isActionUp) {
else if (isActionUp) {
NativeLibrary.onTouchEvent(0f, 0f, false) NativeLibrary.onTouchEvent(0f, 0f, false)
break // Up and down actions shouldn't loop break // Up and down actions shouldn't loop
} }

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project // Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
@ -18,15 +18,27 @@ object EmulationLifecycleUtil {
} }
fun addShutdownHook(hook: Runnable) { fun addShutdownHook(hook: Runnable) {
shutdownHooks.add(hook) if (shutdownHooks.contains(hook)) {
Log.warning("[EmulationLifecycleUtil] Tried to add shutdown hook for function that already existed. Skipping.")
} else {
shutdownHooks.add(hook)
}
} }
fun addPauseResumeHook(hook: Runnable) { fun addPauseResumeHook(hook: Runnable) {
pauseResumeHooks.add(hook) if (pauseResumeHooks.contains(hook)) {
Log.warning("[EmulationLifecycleUtil] Tried to add pause resume hook for function that already existed. Skipping.")
} else {
pauseResumeHooks.add(hook)
}
} }
fun clear() { fun removeHook(hook: Runnable) {
pauseResumeHooks.clear() if (pauseResumeHooks.contains(hook)) {
shutdownHooks.clear() pauseResumeHooks.remove(hook)
}
if (shutdownHooks.contains(hook)) {
shutdownHooks.remove(hook)
}
} }
} }

View File

@ -657,6 +657,25 @@ void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEn
window->OnTouchMoved((int)x, (int)y); window->OnTouchMoved((int)x, (int)y);
} }
jboolean Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchEvent([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jobject obj,
jfloat x, jfloat y,
jboolean pressed) {
if (!secondary_window) {
return JNI_FALSE;
}
return static_cast<jboolean>(secondary_window->OnTouchEvent(
static_cast<int>(x + 0.5), static_cast<int>(y + 0.5), pressed));
}
void Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchMoved([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jobject obj,
jfloat x, jfloat y) {
if (secondary_window) {
secondary_window->OnTouchMoved((int)x, (int)y);
}
}
jlong Java_org_citra_citra_1emu_NativeLibrary_getTitleId(JNIEnv* env, [[maybe_unused]] jobject obj, jlong Java_org_citra_citra_1emu_NativeLibrary_getTitleId(JNIEnv* env, [[maybe_unused]] jobject obj,
jstring j_filename) { jstring j_filename) {
std::string filepath = GetJString(env, j_filename); std::string filepath = GetJString(env, j_filename);

View File

@ -193,6 +193,10 @@
<string name="region_mismatch">Advertiment Regió No Vàlida</string> <string name="region_mismatch">Advertiment Regió No Vàlida</string>
<string name="region_mismatch_emulated">La configuració del país no és vàlida per a la regió emulada seleccionada.</string> <string name="region_mismatch_emulated">La configuració del país no és vàlida per a la regió emulada seleccionada.</string>
<string name="region_mismatch_console">La configuració del país no és vàlida per a la consola vinculada actual.</string> <string name="region_mismatch_console">La configuració del país no és vàlida per a la consola vinculada actual.</string>
<string name="storage">Emmagatzematge</string>
<string name="compress_cia_installs">Comprimir el contingut de CIAs instal·lats</string>
<string name="compress_cia_installs_description">Comprimix el contingut de fitxers CIA quan són instal·lats a la SD emulada. Només afecta contingut CIA instal·lat amb esta opció activada.</string>
<!-- Camera settings strings --> <!-- Camera settings strings -->
<string name="inner_camera">Càmera interior</string> <string name="inner_camera">Càmera interior</string>
<string name="outer_left_camera">Càmera esquerra externa</string> <string name="outer_left_camera">Càmera esquerra externa</string>
@ -397,6 +401,10 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="emulation_configure_controls">Configurar Controls</string> <string name="emulation_configure_controls">Configurar Controls</string>
<string name="emulation_edit_layout">Editar Estil</string> <string name="emulation_edit_layout">Editar Estil</string>
<string name="emulation_done">Fet</string> <string name="emulation_done">Fet</string>
<string name="emulation_button_sliding">Lliscament de botons</string>
<string name="emulation_button_sliding_disabled">Mantindre el botó pressionat originalment</string>
<string name="emulation_button_sliding_enabled">Mantindre el botó pressionat actualment</string>
<string name="emulation_button_sliding_alternative">Mantindre el botó original i actualment pressionat</string>
<string name="emulation_toggle_controls">Activar Controls</string> <string name="emulation_toggle_controls">Activar Controls</string>
<string name="emulation_control_scale">Ajustar Escala</string> <string name="emulation_control_scale">Ajustar Escala</string>
<string name="emulation_control_scale_global">Escala Global</string> <string name="emulation_control_scale_global">Escala Global</string>
@ -409,6 +417,8 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="emulation_aspect_ratio">Relació d\'Aspecte</string> <string name="emulation_aspect_ratio">Relació d\'Aspecte</string>
<string name="emulation_switch_screen_layout">Estil de Pantalla Apaïsada</string> <string name="emulation_switch_screen_layout">Estil de Pantalla Apaïsada</string>
<string name="emulation_switch_portrait_layout">Estil de Pantalla de Perfil</string> <string name="emulation_switch_portrait_layout">Estil de Pantalla de Perfil</string>
<string name="emulation_switch_secondary_layout">Estil de Pantalla Secundària</string>
<string name="emulation_switch_secondary_layout_description">La disposició de la pantalla secundària connectada, amb cable o sense fil (Chromecast, Miracast)</string>
<string name="emulation_screen_layout_largescreen">Pantalla amplia</string> <string name="emulation_screen_layout_largescreen">Pantalla amplia</string>
<string name="emulation_screen_layout_portrait">Vertical</string> <string name="emulation_screen_layout_portrait">Vertical</string>
<string name="emulation_screen_layout_single">Pantalla Única</string> <string name="emulation_screen_layout_single">Pantalla Única</string>
@ -416,6 +426,7 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="emulation_screen_layout_hybrid">Pantalles híbrides</string> <string name="emulation_screen_layout_hybrid">Pantalles híbrides</string>
<string name="emulation_screen_layout_original">Original</string> <string name="emulation_screen_layout_original">Original</string>
<string name="emulation_portrait_layout_top_full">Per omissió</string> <string name="emulation_portrait_layout_top_full">Per omissió</string>
<string name="emulation_secondary_display_default">Per defecte del sistema (espill)</string>
<string name="emulation_screen_layout_custom">Estil Personalitzat</string> <string name="emulation_screen_layout_custom">Estil Personalitzat</string>
<string name="emulation_small_screen_position">Posició de Pantalla Xicoteta</string> <string name="emulation_small_screen_position">Posició de Pantalla Xicoteta</string>
<string name="small_screen_position_description">On hauria d\'aparéixer la pantalla xicoteta en relació amb la gran en Proporció de Pantalla Gran?</string> <string name="small_screen_position_description">On hauria d\'aparéixer la pantalla xicoteta en relació amb la gran en Proporció de Pantalla Gran?</string>
@ -536,6 +547,10 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="create_shortcut">Crear drecera</string> <string name="create_shortcut">Crear drecera</string>
<string name="shortcut_name_empty">El nom de la drecera no pot estar buit</string> <string name="shortcut_name_empty">El nom de la drecera no pot estar buit</string>
<string name="shortcut_image_stretch_toggle">Allargar per a ajustar la imatge</string> <string name="shortcut_image_stretch_toggle">Allargar per a ajustar la imatge</string>
<string name="game_context_id">ID:</string>
<string name="game_context_file">Fitxer:</string>
<string name="game_context_type">Tipus:</string>
<!-- Performance Overlay settings --> <!-- Performance Overlay settings -->
<string name="performance_overlay_show">Mostrar informació de rendiment</string> <string name="performance_overlay_show">Mostrar informació de rendiment</string>
<string name="performance_overlay_options">Informació de rendiment</string> <string name="performance_overlay_options">Informació de rendiment</string>

View File

@ -194,7 +194,7 @@
<string name="region_mismatch_emulated">La configuración del país no es válida para la región emulada seleccionada.</string> <string name="region_mismatch_emulated">La configuración del país no es válida para la región emulada seleccionada.</string>
<string name="region_mismatch_console">La configuración del país no es válida para la consola vinculada actual.</string> <string name="region_mismatch_console">La configuración del país no es válida para la consola vinculada actual.</string>
<string name="storage">Almacenamiento</string> <string name="storage">Almacenamiento</string>
<string name="compress_cia_installs">Comprimir el contenido CIA instalado</string> <string name="compress_cia_installs">Comprimir el contenido de CIAs instalados</string>
<string name="compress_cia_installs_description">Comprime el contenido de archivos CIA cuando son instalados a la SD emulada. Solo afecta contenido CIA instalado con esta opción activada.</string> <string name="compress_cia_installs_description">Comprime el contenido de archivos CIA cuando son instalados a la SD emulada. Solo afecta contenido CIA instalado con esta opción activada.</string>
<!-- Camera settings strings --> <!-- Camera settings strings -->
@ -402,9 +402,9 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="emulation_edit_layout">Editar Estilo</string> <string name="emulation_edit_layout">Editar Estilo</string>
<string name="emulation_done">Hecho</string> <string name="emulation_done">Hecho</string>
<string name="emulation_button_sliding">Deslizamiento de botones</string> <string name="emulation_button_sliding">Deslizamiento de botones</string>
<string name="emulation_button_sliding_disabled">Mantenga el botón presionado originalmente</string> <string name="emulation_button_sliding_disabled">Mantener el botón presionado originalmente</string>
<string name="emulation_button_sliding_enabled">Mantenga el botón presionado actualmente</string> <string name="emulation_button_sliding_enabled">Mantener el botón presionado actualmente</string>
<string name="emulation_button_sliding_alternative">Mantenga el botón original y actualmente presionado</string> <string name="emulation_button_sliding_alternative">Mantener el botón original y actualmente presionado</string>
<string name="emulation_toggle_controls">Activar Controles</string> <string name="emulation_toggle_controls">Activar Controles</string>
<string name="emulation_control_scale">Ajustar Escala</string> <string name="emulation_control_scale">Ajustar Escala</string>
<string name="emulation_control_scale_global">Escala Global</string> <string name="emulation_control_scale_global">Escala Global</string>
@ -417,6 +417,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="emulation_aspect_ratio">Relación de Aspecto</string> <string name="emulation_aspect_ratio">Relación de Aspecto</string>
<string name="emulation_switch_screen_layout">Estilo de Pantalla Apaisada</string> <string name="emulation_switch_screen_layout">Estilo de Pantalla Apaisada</string>
<string name="emulation_switch_portrait_layout">Estilo de Pantalla de Perfil</string> <string name="emulation_switch_portrait_layout">Estilo de Pantalla de Perfil</string>
<string name="emulation_switch_secondary_layout">Estilo de Pantalla Secundaria</string>
<string name="emulation_switch_secondary_layout_description">El estilo de la pantalla secundaria conectada, con cable o inalámbrica (Chromecast, Miracast)</string>
<string name="emulation_screen_layout_largescreen">Pantalla amplia</string> <string name="emulation_screen_layout_largescreen">Pantalla amplia</string>
<string name="emulation_screen_layout_portrait">Retrato</string> <string name="emulation_screen_layout_portrait">Retrato</string>
<string name="emulation_screen_layout_single">Pantalla Única</string> <string name="emulation_screen_layout_single">Pantalla Única</string>
@ -424,6 +426,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="emulation_screen_layout_hybrid">Pantallas híbridas</string> <string name="emulation_screen_layout_hybrid">Pantallas híbridas</string>
<string name="emulation_screen_layout_original">Original</string> <string name="emulation_screen_layout_original">Original</string>
<string name="emulation_portrait_layout_top_full">Por defecto</string> <string name="emulation_portrait_layout_top_full">Por defecto</string>
<string name="emulation_secondary_display_default">Por defecto del sistema (espejo)</string>
<string name="emulation_screen_layout_custom">Estilo personalizado</string> <string name="emulation_screen_layout_custom">Estilo personalizado</string>
<string name="emulation_small_screen_position">Posición Pantalla Pequeña</string> <string name="emulation_small_screen_position">Posición Pantalla Pequeña</string>
<string name="small_screen_position_description">¿Dónde debería aparecer la pantalla pequeña en relación con la grande en Disposicion de Pantalla Grande?</string> <string name="small_screen_position_description">¿Dónde debería aparecer la pantalla pequeña en relación con la grande en Disposicion de Pantalla Grande?</string>

View File

@ -417,6 +417,7 @@
<string name="emulation_switch_screen_layout">Geometryczny Układ Ekranu</string> <string name="emulation_switch_screen_layout">Geometryczny Układ Ekranu</string>
<string name="emulation_switch_portrait_layout">Pionowy Układ Ekranu</string> <string name="emulation_switch_portrait_layout">Pionowy Układ Ekranu</string>
<string name="emulation_switch_secondary_layout">Układ ekranu wyświetlacza dodatkowego</string> <string name="emulation_switch_secondary_layout">Układ ekranu wyświetlacza dodatkowego</string>
<string name="emulation_switch_secondary_layout_description">Układ używany przez podłączony dodatkowy ekran, przewodowy lub bezprzewodowy (Chromecast, Miracast)</string>
<string name="emulation_screen_layout_largescreen">Duży Ekran</string> <string name="emulation_screen_layout_largescreen">Duży Ekran</string>
<string name="emulation_screen_layout_portrait">Ekran</string> <string name="emulation_screen_layout_portrait">Ekran</string>
<string name="emulation_screen_layout_single">Pojedynczy ekran</string> <string name="emulation_screen_layout_single">Pojedynczy ekran</string>
@ -424,6 +425,7 @@
<string name="emulation_screen_layout_hybrid">Hybrydowy Ekran</string> <string name="emulation_screen_layout_hybrid">Hybrydowy Ekran</string>
<string name="emulation_screen_layout_original">Oryginalny</string> <string name="emulation_screen_layout_original">Oryginalny</string>
<string name="emulation_portrait_layout_top_full">Domyślny</string> <string name="emulation_portrait_layout_top_full">Domyślny</string>
<string name="emulation_secondary_display_default">Ustawienia domyślne systemu (mirror)</string>
<string name="emulation_screen_layout_custom">Niestandardowy Układ</string> <string name="emulation_screen_layout_custom">Niestandardowy Układ</string>
<string name="emulation_small_screen_position">Pozycja małego ekranu</string> <string name="emulation_small_screen_position">Pozycja małego ekranu</string>
<string name="small_screen_position_description">Gdzie powinien być wyświetlany mały ekran względem dużego w układzie dużego ekranu?</string> <string name="small_screen_position_description">Gdzie powinien być wyświetlany mały ekran względem dużego w układzie dużego ekranu?</string>

View File

@ -60,6 +60,10 @@ if (ENABLE_QT AND UNIX AND NOT APPLE)
target_link_libraries(citra_meta PRIVATE Qt6::DBus gamemode) target_link_libraries(citra_meta PRIVATE Qt6::DBus gamemode)
endif() endif()
if (ENABLE_QT AND APPLE)
target_link_libraries(citra_meta PRIVATE Qt6::GuiPrivate)
endif()
if (ENABLE_QT AND USE_DISCORD_PRESENCE) if (ENABLE_QT AND USE_DISCORD_PRESENCE)
target_link_libraries(citra_meta PRIVATE discord-rpc) target_link_libraries(citra_meta PRIVATE discord-rpc)
endif() endif()

View File

@ -172,12 +172,12 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL
multiplayer/state.h multiplayer/state.h
multiplayer/validation.h multiplayer/validation.h
precompiled_headers.h precompiled_headers.h
qt_image_interface.cpp
qt_image_interface.h
uisettings.cpp uisettings.cpp
uisettings.h uisettings.h
user_data_migration.cpp user_data_migration.cpp
user_data_migration.h user_data_migration.h
qt_image_interface.cpp
qt_image_interface.h
util/clickable_label.cpp util/clickable_label.cpp
util/clickable_label.h util/clickable_label.h
util/graphics_device_info.cpp util/graphics_device_info.cpp
@ -190,6 +190,13 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL
util/util.h util/util.h
) )
if (APPLE)
target_sources(citra_qt PUBLIC
qt_swizzle.h
qt_swizzle.mm
)
endif()
file(GLOB COMPAT_LIST file(GLOB COMPAT_LIST
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
@ -275,6 +282,10 @@ if (NOT WIN32)
target_include_directories(citra_qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) target_include_directories(citra_qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif() endif()
if (APPLE)
target_link_libraries(citra_qt PRIVATE Qt6::GuiPrivate)
endif()
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
target_link_libraries(citra_qt PRIVATE Qt6::DBus gamemode) target_link_libraries(citra_qt PRIVATE Qt6::DBus gamemode)
endif() endif()

View File

@ -69,6 +69,7 @@
#include "citra_qt/movie/movie_record_dialog.h" #include "citra_qt/movie/movie_record_dialog.h"
#include "citra_qt/multiplayer/state.h" #include "citra_qt/multiplayer/state.h"
#include "citra_qt/qt_image_interface.h" #include "citra_qt/qt_image_interface.h"
#include "citra_qt/qt_swizzle.h"
#include "citra_qt/uisettings.h" #include "citra_qt/uisettings.h"
#include "common/play_time_manager.h" #include "common/play_time_manager.h"
#ifdef ENABLE_QT_UPDATE_CHECKER #ifdef ENABLE_QT_UPDATE_CHECKER
@ -4112,6 +4113,11 @@ static Qt::HighDpiScaleFactorRoundingPolicy GetHighDpiRoundingPolicy() {
} }
void LaunchQtFrontend(int argc, char* argv[]) { void LaunchQtFrontend(int argc, char* argv[]) {
#ifdef __APPLE__
// Ensure that the linker doesn't optimize qt_swizzle.mm out of existence.
QtSwizzle::Dummy();
#endif
Common::DetachedTasks detached_tasks; Common::DetachedTasks detached_tasks;
#if MICROPROFILE_ENABLED #if MICROPROFILE_ENABLED

View File

@ -0,0 +1,9 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
namespace QtSwizzle {
void Dummy();
} // namespace QtSwizzle

View File

@ -0,0 +1,48 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#import <QtGui/private/qmetallayer_p.h>
#import <objc/runtime.h>
namespace QtSwizzle {
void Dummy() {
// Call this anywhere to make sure that qt_swizzle.mm is linked.
// noop
}
} // namespace QtSwizzle
@implementation QMetalLayer (AzaharPatch)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class targetClass = [self class];
// Get the original and swizzled methods
Method originalMethod =
class_getInstanceMethod(targetClass, @selector(setNeedsDisplayInRect:));
Method swizzledMethod =
class_getInstanceMethod(targetClass, @selector(swizzled_setNeedsDisplayInRect:));
// Swap the implementations
method_exchangeImplementations(originalMethod, swizzledMethod);
});
}
- (void)swizzled_setNeedsDisplayInRect:(CGRect)rect {
constexpr auto tooBig = 1e10; // Arbitrary large number
// Check for problematic huge rectangles
if ((!self.needsDisplay) && (rect.size.width > tooBig || rect.size.height > tooBig ||
rect.origin.x < -tooBig || rect.origin.y < -tooBig)) {
return;
}
// Call the original implementation
[self swizzled_setNeedsDisplayInRect:rect];
}
@end

View File

@ -66,6 +66,10 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns
} }
#endif #endif
if (!layout.bottom_screen_enabled) {
return false;
}
Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue();
if (render_3d_mode == Settings::StereoRenderOption::SideBySide || if (render_3d_mode == Settings::StereoRenderOption::SideBySide ||

View File

@ -864,8 +864,10 @@ bool CIAFile::Close() {
if (!complete) { if (!complete) {
LOG_ERROR(Service_AM, "CIAFile closed prematurely, aborting install..."); LOG_ERROR(Service_AM, "CIAFile closed prematurely, aborting install...");
if (!is_additional_content) { if (!is_additional_content) {
FileUtil::DeleteDirRecursively( // Only delete the content folder as there may be user save data in the title folder.
GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID())); const std::string title_content_path =
GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID()) + "content/";
FileUtil::DeleteDirRecursively(title_content_path);
} }
return true; return true;
} }

View File

@ -556,12 +556,15 @@ bool PipelineCache::EnsureDirectories() const {
}; };
return create_dir(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) && return create_dir(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) &&
create_dir(GetPipelineCacheDir()); create_dir(GetVulkanDir()) && create_dir(GetPipelineCacheDir());
}
std::string PipelineCache::GetVulkanDir() const {
return FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir) + "vulkan" + DIR_SEP;
} }
std::string PipelineCache::GetPipelineCacheDir() const { std::string PipelineCache::GetPipelineCacheDir() const {
return FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir) + "vulkan" + DIR_SEP + "pipeline" + return GetVulkanDir() + "pipeline" + DIR_SEP;
DIR_SEP;
} }
void PipelineCache::SwitchPipelineCache(u64 title_id, const std::atomic_bool& stop_loading, void PipelineCache::SwitchPipelineCache(u64 title_id, const std::atomic_bool& stop_loading,

View File

@ -108,6 +108,9 @@ private:
/// Create pipeline cache directories. Returns true on success. /// Create pipeline cache directories. Returns true on success.
bool EnsureDirectories() const; bool EnsureDirectories() const;
/// Returns the Vulkan shader directory
std::string GetVulkanDir() const;
/// Returns the pipeline cache storage dir /// Returns the pipeline cache storage dir
std::string GetPipelineCacheDir() const; std::string GetPipelineCacheDir() const;

View File

@ -7,7 +7,7 @@ The scripts in this directory assume that your current working directory is the
## Pre-release checklist ## Pre-release checklist
- [ ] Update compatibility list - [ ] Update compatibility list
- [ ] Update translations - [ ] If this is a major release (2123.1 -> major.minor), update translations
### Note: ### Note:

6
tools/purge-github-cache.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash -ex
# This script assumes that the Github CLI is installed and that
# the authenticated user has appropriate authorization.
gh cache delete --all