summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/scripts/common/post-upload.sh4
-rw-r--r--.ci/scripts/windows/upload.ps110
-rw-r--r--.gitignore2
-rw-r--r--.reuse/dep513
-rw-r--r--dist/english_plurals/README.md19
-rw-r--r--dist/english_plurals/en.ts67
-rw-r--r--dist/qt_themes/colorful/icons/48x48/list-add.png (renamed from dist/qt_themes/colorful/icons/48x48/plus.png)bin496 -> 496 bytes
-rw-r--r--dist/qt_themes/colorful/style.qrc2
-rw-r--r--dist/qt_themes/colorful_dark/icons/16x16/refresh.pngbin362 -> 0 bytes
-rw-r--r--dist/qt_themes/colorful_dark/icons/index.theme2
-rw-r--r--dist/qt_themes/colorful_dark/style.qrc2
-rw-r--r--dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.pngbin362 -> 0 bytes
-rw-r--r--dist/qt_themes/colorful_midnight_blue/style.qrc2
-rw-r--r--dist/qt_themes/default/default.qrc2
-rw-r--r--dist/qt_themes/default/icons/16x16/refresh.pngbin349 -> 0 bytes
-rw-r--r--dist/qt_themes/default/icons/48x48/list-add.png (renamed from dist/qt_themes/default/icons/48x48/plus.png)bin316 -> 316 bytes
-rw-r--r--dist/qt_themes/default_dark/icons/index.theme8
-rw-r--r--dist/qt_themes/default_dark/style.qrc25
-rw-r--r--dist/qt_themes/default_dark/style.qss687
-rw-r--r--dist/qt_themes/qdarkstyle/icons/16x16/refresh.pngbin362 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/icons/48x48/list-add.png (renamed from dist/qt_themes/qdarkstyle/icons/48x48/plus.png)bin339 -> 339 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/style.qrc2
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.pngbin304 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.pngbin362 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.pngbin362 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.pngbin3438 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.pngbin1098 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.pngbin15120 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.pngbin542 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.pngbin339 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.pngbin676 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.pngbin725 -> 0 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qrc19
-rw-r--r--src/audio_core/sink/cubeb_sink.cpp3
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/common/settings.h2
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp15
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp3
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp31
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/file_sys/ips_layer.cpp3
-rw-r--r--src/core/hid/emulated_controller.cpp30
-rw-r--r--src/core/hid/emulated_controller.h7
-rw-r--r--src/core/hid/hid_types.h12
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp77
-rw-r--r--src/core/hle/service/ldn/errors.h12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp436
-rw-r--r--src/core/hle/service/ldn/ldn.h6
-rw-r--r--src/core/hle/service/ldn/ldn_results.h27
-rw-r--r--src/core/hle/service/ldn/ldn_types.h284
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp5
-rw-r--r--src/yuzu/CMakeLists.txt14
-rw-r--r--src/yuzu/aboutdialog.ui3
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_audio.ui4
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp1
-rw-r--r--src/yuzu/game_list.cpp2
-rw-r--r--src/yuzu/game_list_p.h2
-rw-r--r--src/yuzu/main.cpp106
-rw-r--r--src/yuzu/main.h5
-rw-r--r--src/yuzu/multiplayer/direct_connect.ui2
63 files changed, 1808 insertions, 161 deletions
diff --git a/.ci/scripts/common/post-upload.sh b/.ci/scripts/common/post-upload.sh
index 7f910b2b3..0930b7a7b 100644
--- a/.ci/scripts/common/post-upload.sh
+++ b/.ci/scripts/common/post-upload.sh
@@ -8,8 +8,10 @@ cp LICENSE.txt "$DIR_NAME"
8cp README.md "$DIR_NAME" 8cp README.md "$DIR_NAME"
9 9
10if [[ -z "${NO_SOURCE_PACK}" ]]; then 10if [[ -z "${NO_SOURCE_PACK}" ]]; then
11 tar -cJvf "${REV_NAME}-source.tar.xz" src externals CMakeLists.txt README.md LICENSE.txt 11 git clone --depth 1 file://$(readlink -e .) ${REV_NAME}-source
12 tar -cJvf "${REV_NAME}-source.tar.xz" ${REV_NAME}-source
12 cp -v "${REV_NAME}-source.tar.xz" "$DIR_NAME" 13 cp -v "${REV_NAME}-source.tar.xz" "$DIR_NAME"
14 cp -v "${REV_NAME}-source.tar.xz" "${ARTIFACTS_DIR}/"
13fi 15fi
14 16
15tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$DIR_NAME" 17tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$DIR_NAME"
diff --git a/.ci/scripts/windows/upload.ps1 b/.ci/scripts/windows/upload.ps1
index f2368be6f..d463281de 100644
--- a/.ci/scripts/windows/upload.ps1
+++ b/.ci/scripts/windows/upload.ps1
@@ -42,14 +42,10 @@ mkdir $RELEASE_DIST
42mkdir $MSVC_SOURCE 42mkdir $MSVC_SOURCE
43mkdir "artifacts" 43mkdir "artifacts"
44 44
45$CURRENT_DIR = Convert-Path .
46
45# Build a tar.xz for the source of the release 47# Build a tar.xz for the source of the release
46Copy-Item .\LICENSE.txt -Destination $MSVC_SOURCE 48git clone --depth 1 file://$CURRENT_DIR $MSVC_SOURCE
47Copy-Item .\README.md -Destination $MSVC_SOURCE
48Copy-Item .\CMakeLists.txt -Destination $MSVC_SOURCE
49Copy-Item .\src -Recurse -Destination $MSVC_SOURCE
50Copy-Item .\externals -Recurse -Destination $MSVC_SOURCE
51Copy-Item .\dist -Recurse -Destination $MSVC_SOURCE
52Copy-Item .\CMakeModules -Recurse -Destination $MSVC_SOURCE
537z a -r -ttar $MSVC_SOURCE_TAR $MSVC_SOURCE 497z a -r -ttar $MSVC_SOURCE_TAR $MSVC_SOURCE
547z a -r -txz $MSVC_SOURCE_TARXZ $MSVC_SOURCE_TAR 507z a -r -txz $MSVC_SOURCE_TARXZ $MSVC_SOURCE_TAR
55 51
diff --git a/.gitignore b/.gitignore
index 6207765d8..cdf37962a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,7 @@ doc-build/
7 7
8# Generated source files 8# Generated source files
9src/common/scm_rev.cpp 9src/common/scm_rev.cpp
10.travis.descriptor.json 10dist/english_plurals/generated_en.ts
11 11
12# Project/editor files 12# Project/editor files
13*.swp 13*.swp
diff --git a/.reuse/dep5 b/.reuse/dep5
index e2ee4f456..5f31a4f55 100644
--- a/.reuse/dep5
+++ b/.reuse/dep5
@@ -2,7 +2,8 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2Comment: It is best to use this file to record copyright information about 2Comment: It is best to use this file to record copyright information about
3 generated, binary and third party files 3 generated, binary and third party files
4 4
5Files: dist/icons/controller/*.png 5Files: dist/english_plurals/*
6 dist/icons/controller/*.png
6 dist/icons/overlay/*.png 7 dist/icons/overlay/*.png
7 dist/languages/* 8 dist/languages/*
8 dist/qt_themes/*/icons/index.theme 9 dist/qt_themes/*/icons/index.theme
@@ -41,20 +42,18 @@ Files: dist/qt_themes/*/icons/16x16/connected.png
41 dist/qt_themes/*/icons/48x48/sd_card.png 42 dist/qt_themes/*/icons/48x48/sd_card.png
42 dist/qt_themes/*/icons/48x48/star.png 43 dist/qt_themes/*/icons/48x48/star.png
43 dist/qt_themes/*/icons/256x256/plus_folder.png 44 dist/qt_themes/*/icons/256x256/plus_folder.png
44 dist/qt_themes/colorful/icons/48x48/plus.png 45 dist/qt_themes/colorful/icons/48x48/list-add.png
45 dist/qt_themes/default/icons/16x16/checked.png 46 dist/qt_themes/default/icons/16x16/checked.png
46 dist/qt_themes/default/icons/16x16/failed.png 47 dist/qt_themes/default/icons/16x16/failed.png
47Copyright: https://icons8.com 48Copyright: https://icons8.com
48License: CC-BY-ND-3.0 49License: CC-BY-ND-3.0
49 50
50Files: dist/qt_themes/*/icons/16x16/refresh.png 51Files: dist/qt_themes/*/icons/16x16/view-refresh.png
51 dist/qt_themes/*/icons/16x16/view-refresh.png
52Copyright: Google, Inc. 52Copyright: Google, Inc.
53License: Apache-2.0 53License: Apache-2.0
54 54
55Files: dist/qt_themes/default/icons/48x48/plus.png 55Files: dist/qt_themes/default/icons/48x48/list-add.png
56 dist/qt_themes/qdarkstyle/icons/48x48/plus.png 56 dist/qt_themes/qdarkstyle/icons/48x48/list-add.png
57 dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png
58Copyright: BreadFish64 57Copyright: BreadFish64
59License: CC0-1.0 58License: CC0-1.0
60 59
diff --git a/dist/english_plurals/README.md b/dist/english_plurals/README.md
new file mode 100644
index 000000000..a4954f6a6
--- /dev/null
+++ b/dist/english_plurals/README.md
@@ -0,0 +1,19 @@
1# English Plurals
2
3Qt has "Translation Rules for Plurals", small example
4
5 // Take a source line like
6 tr("Building: %n shader(s)", "", i)
7
8 // i = 1:
9 Building: 1 shader
10 // i = 2:
11 Building: 2 shaders
12
13For yuzu the source language used is English, for all other languages handling of plurals is handled by Qt and the translation collaboration site. Handling plurals in the source language (English) requires special consideration.
14
15With CMake flag GENERATE_QT_TRANSLATION a generated_en.ts file is created from the source. It ignored by git (`.gitignore` in the project root). It is placed in this directory so that the relative refrences with the source code is correct.
16
17Having the plurals look nice isn't critical, and automation to use translation collaboration sites may require specifing the project language as "Pirate English", so this has been done manually.
18
19The en.ts in this directory is taken from a build, edited in Qt Linguist and then committed. As the code is in XML, using the tool is not strictly required.
diff --git a/dist/english_plurals/en.ts b/dist/english_plurals/en.ts
new file mode 100644
index 000000000..172cd4bba
--- /dev/null
+++ b/dist/english_plurals/en.ts
@@ -0,0 +1,67 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!DOCTYPE TS>
3<TS version="2.1" language="en_US" sourcelanguage="en_US">
4<context>
5 <name>GMainWindow</name>
6 <message numerus="yes">
7 <location filename="../../src/yuzu/main.cpp" line="2322"/>
8 <source>%n file(s) remaining</source>
9 <translation>
10 <numerusform>%n file remaining</numerusform>
11 <numerusform>%n files remaining</numerusform>
12 </translation>
13 </message>
14 <message numerus="yes">
15 <location filename="../../src/yuzu/main.cpp" line="2377"/>
16 <source>%n file(s) were newly installed
17</source>
18 <translation>
19 <numerusform>%n file was newly installed
20</numerusform>
21 <numerusform>%n files were newly installed
22</numerusform>
23 </translation>
24 </message>
25 <message numerus="yes">
26 <location filename="../../src/yuzu/main.cpp" line="2380"/>
27 <source>%n file(s) were overwritten
28</source>
29 <translation>
30 <numerusform>%n file was overwritten
31</numerusform>
32 <numerusform>%n were overwritten
33</numerusform>
34 </translation>
35 </message>
36 <message numerus="yes">
37 <location filename="../../src/yuzu/main.cpp" line="2382"/>
38 <source>%n file(s) failed to install
39</source>
40 <translation>
41 <numerusform>%n file failed to install
42</numerusform>
43 <numerusform>%n files failed to install
44</numerusform>
45 </translation>
46 </message>
47 <message numerus="yes">
48 <location filename="../../src/yuzu/main.cpp" line="3264"/>
49 <source>Building: %n shader(s)</source>
50 <translation>
51 <numerusform>Building: %n shader</numerusform>
52 <numerusform>Building: %n shaders</numerusform>
53 </translation>
54 </message>
55</context>
56<context>
57 <name>GameListSearchField</name>
58 <message numerus="yes">
59 <location filename="../../src/yuzu/game_list.cpp" line="87"/>
60 <source>%1 of %n result(s)</source>
61 <translation>
62 <numerusform>%1 of %n result</numerusform>
63 <numerusform>%1 of %n results</numerusform>
64 </translation>
65 </message>
66</context>
67</TS>
diff --git a/dist/qt_themes/colorful/icons/48x48/plus.png b/dist/qt_themes/colorful/icons/48x48/list-add.png
index bc2c47c91..bc2c47c91 100644
--- a/dist/qt_themes/colorful/icons/48x48/plus.png
+++ b/dist/qt_themes/colorful/icons/48x48/list-add.png
Binary files differ
diff --git a/dist/qt_themes/colorful/style.qrc b/dist/qt_themes/colorful/style.qrc
index 4b3f28d89..507e0e58b 100644
--- a/dist/qt_themes/colorful/style.qrc
+++ b/dist/qt_themes/colorful/style.qrc
@@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
13 <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> 13 <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
14 <file alias="48x48/chip.png">icons/48x48/chip.png</file> 14 <file alias="48x48/chip.png">icons/48x48/chip.png</file>
15 <file alias="48x48/folder.png">icons/48x48/folder.png</file> 15 <file alias="48x48/folder.png">icons/48x48/folder.png</file>
16 <file alias="48x48/plus.png">icons/48x48/plus.png</file> 16 <file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
17 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> 17 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
18 <file alias="48x48/star.png">icons/48x48/star.png</file> 18 <file alias="48x48/star.png">icons/48x48/star.png</file>
19 <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> 19 <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
diff --git a/dist/qt_themes/colorful_dark/icons/16x16/refresh.png b/dist/qt_themes/colorful_dark/icons/16x16/refresh.png
deleted file mode 100644
index d4afd76f9..000000000
--- a/dist/qt_themes/colorful_dark/icons/16x16/refresh.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/colorful_dark/icons/index.theme b/dist/qt_themes/colorful_dark/icons/index.theme
index 19dc0369a..b37a06df7 100644
--- a/dist/qt_themes/colorful_dark/icons/index.theme
+++ b/dist/qt_themes/colorful_dark/icons/index.theme
@@ -3,6 +3,6 @@ Name=colorful_dark
3Comment=Colorful theme (Dark style) 3Comment=Colorful theme (Dark style)
4Inherits=colorful 4Inherits=colorful
5Directories=16x16 5Directories=16x16
6 6
7[16x16] 7[16x16]
8Size=16 8Size=16
diff --git a/dist/qt_themes/colorful_dark/style.qrc b/dist/qt_themes/colorful_dark/style.qrc
index 50e78c37b..9853fd438 100644
--- a/dist/qt_themes/colorful_dark/style.qrc
+++ b/dist/qt_themes/colorful_dark/style.qrc
@@ -15,7 +15,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
15 <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file> 15 <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
16 <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file> 16 <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
17 <file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file> 17 <file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
18 <file alias="48x48/plus.png">../colorful/icons/48x48/plus.png</file> 18 <file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
19 <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file> 19 <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
20 <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file> 20 <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
21 </qresource> 21 </qresource>
diff --git a/dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png b/dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png
deleted file mode 100644
index d4afd76f9..000000000
--- a/dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/colorful_midnight_blue/style.qrc b/dist/qt_themes/colorful_midnight_blue/style.qrc
index ac8cb0d49..1081d281d 100644
--- a/dist/qt_themes/colorful_midnight_blue/style.qrc
+++ b/dist/qt_themes/colorful_midnight_blue/style.qrc
@@ -11,7 +11,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
11 <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file> 11 <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
12 <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file> 12 <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
13 <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file> 13 <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
14 <file alias="48x48/plus.png">../colorful/icons/48x48/plus.png</file> 14 <file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
15 <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file> 15 <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
16 <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file> 16 <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
17 </qresource> 17 </qresource>
diff --git a/dist/qt_themes/default/default.qrc b/dist/qt_themes/default/default.qrc
index ef080c221..a07f2a9c1 100644
--- a/dist/qt_themes/default/default.qrc
+++ b/dist/qt_themes/default/default.qrc
@@ -17,7 +17,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
17 <file alias="48x48/chip.png">icons/48x48/chip.png</file> 17 <file alias="48x48/chip.png">icons/48x48/chip.png</file>
18 <file alias="48x48/folder.png">icons/48x48/folder.png</file> 18 <file alias="48x48/folder.png">icons/48x48/folder.png</file>
19 <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file> 19 <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
20 <file alias="48x48/plus.png">icons/48x48/plus.png</file> 20 <file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
21 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> 21 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
22 <file alias="48x48/star.png">icons/48x48/star.png</file> 22 <file alias="48x48/star.png">icons/48x48/star.png</file>
23 <file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file> 23 <file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file>
diff --git a/dist/qt_themes/default/icons/16x16/refresh.png b/dist/qt_themes/default/icons/16x16/refresh.png
deleted file mode 100644
index 69f9474ac..000000000
--- a/dist/qt_themes/default/icons/16x16/refresh.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/default/icons/48x48/plus.png b/dist/qt_themes/default/icons/48x48/list-add.png
index dbc74687b..dbc74687b 100644
--- a/dist/qt_themes/default/icons/48x48/plus.png
+++ b/dist/qt_themes/default/icons/48x48/list-add.png
Binary files differ
diff --git a/dist/qt_themes/default_dark/icons/index.theme b/dist/qt_themes/default_dark/icons/index.theme
new file mode 100644
index 000000000..60a072d1d
--- /dev/null
+++ b/dist/qt_themes/default_dark/icons/index.theme
@@ -0,0 +1,8 @@
1[Icon Theme]
2Name=default_dark
3Comment=Colorful theme (Dark style)
4Inherits=colorful
5Directories=16x16
6
7[16x16]
8Size=16
diff --git a/dist/qt_themes/default_dark/style.qrc b/dist/qt_themes/default_dark/style.qrc
new file mode 100644
index 000000000..7de4737c2
--- /dev/null
+++ b/dist/qt_themes/default_dark/style.qrc
@@ -0,0 +1,25 @@
1<!--
2SPDX-FileCopyrightText: 2022 yuzu Emulator Project
3SPDX-License-Identifier: GPL-2.0-or-later
4-->
5<RCC>
6 <qresource prefix="icons/default_dark">
7 <file alias="16x16/connected.png">../colorful/icons/16x16/connected.png</file>
8 <file alias="16x16/connected_notification.png">../colorful/icons/16x16/connected_notification.png</file>
9 <file alias="16x16/disconnected.png">../colorful/icons/16x16/disconnected.png</file>
10 <file alias="index.theme">icons/index.theme</file>
11 <file alias="16x16/lock.png">../colorful_dark/icons/16x16/lock.png</file>
12 <file alias="16x16/view-refresh.png">../colorful_dark/icons/16x16/view-refresh.png</file>
13 <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
14 <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
15 <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
16 <file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
17 <file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
18 <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
19 <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
20 </qresource>
21
22 <qresource prefix="default_dark">
23 <file>style.qss</file>
24 </qresource>
25</RCC>
diff --git a/dist/qt_themes/default_dark/style.qss b/dist/qt_themes/default_dark/style.qss
new file mode 100644
index 000000000..ca6daa2d5
--- /dev/null
+++ b/dist/qt_themes/default_dark/style.qss
@@ -0,0 +1,687 @@
1/*
2* SPDX-FileCopyrightText: 2018 yuzu Emulator Project
3* SPDX-License-Identifier: GPL-2.0-or-later
4*/
5QAbstractSpinBox {
6 min-height: 19px;
7}
8
9QPushButton#TogglableStatusBarButton {
10 color: #959595;
11 border: 1px solid transparent;
12 background-color: transparent;
13 padding: 0px 3px 0px 3px;
14 text-align: center;
15}
16
17QPushButton#TogglableStatusBarButton:checked {
18 color: palette(text);
19}
20
21QPushButton#TogglableStatusBarButton:hover {
22 border: 1px solid #76797C;
23}
24
25QPushButton#RendererStatusBarButton {
26 color: #656565;
27 border: 1px solid transparent;
28 background-color: transparent;
29 padding: 0px 3px 0px 3px;
30 text-align: center;
31}
32
33QPushButton#RendererStatusBarButton:hover {
34 border: 1px solid #76797C;
35}
36
37QPushButton#RendererStatusBarButton:checked {
38 color: #e85c00;
39}
40
41QPushButton#RendererStatusBarButton:!checked {
42 color: #00ccdd;
43}
44
45QPushButton#GPUStatusBarButton {
46 color: #656565;
47 border: 1px solid transparent;
48 background-color: transparent;
49 padding: 0px 3px 0px 3px;
50 text-align: center;
51}
52
53QPushButton#GPUStatusBarButton:hover {
54 border: 1px solid #76797C;
55}
56
57QPushButton#GPUStatusBarButton:checked {
58 color: #ff8040;
59}
60
61QPushButton#GPUStatusBarButton:!checked {
62 color: #40dd40;
63}
64
65QPushButton#DockingStatusBarButton {
66 min-width: 0px;
67 color: palette(text);
68 border: 1px solid transparent;
69 background-color: transparent;
70 padding: 0px 3px 0px 3px;
71 text-align: center;
72}
73
74QPushButton#DockingStatusBarButton:hover {
75 border: 1px solid #76797C;
76}
77
78QPushButton#buttonRefreshDevices {
79 min-width: 21px;
80 min-height: 21px;
81 max-width: 21px;
82 max-height: 21px;
83}
84
85QWidget#bottomPerGameInput,
86QWidget#topControllerApplet,
87QWidget#bottomControllerApplet,
88QGroupBox#groupPlayer1Connected:checked,
89QGroupBox#groupPlayer2Connected:checked,
90QGroupBox#groupPlayer3Connected:checked,
91QGroupBox#groupPlayer4Connected:checked,
92QGroupBox#groupPlayer5Connected:checked,
93QGroupBox#groupPlayer6Connected:checked,
94QGroupBox#groupPlayer7Connected:checked,
95QGroupBox#groupPlayer8Connected:checked {
96 background-color: #f5f5f5;
97}
98
99QWidget#topControllerApplet {
100 border-bottom: 1px solid #828790
101}
102
103QWidget#bottomPerGameInput,
104QWidget#bottomControllerApplet {
105 border-top: 1px solid #828790
106}
107
108QWidget#topPerGameInput,
109QWidget#middleControllerApplet {
110 background-color: #fff;
111}
112
113QWidget#topPerGameInput QComboBox,
114QWidget#middleControllerApplet QComboBox {
115 width: 120px;
116}
117
118QWidget#connectedControllers {
119 background: transparent;
120}
121
122QWidget#playersSupported,
123QWidget#controllersSupported,
124QWidget#controllerSupported1,
125QWidget#controllerSupported2,
126QWidget#controllerSupported3,
127QWidget#controllerSupported4,
128QWidget#controllerSupported5,
129QWidget#controllerSupported6 {
130 border: none;
131 background: transparent;
132}
133
134QGroupBox#groupPlayer1Connected,
135QGroupBox#groupPlayer2Connected,
136QGroupBox#groupPlayer3Connected,
137QGroupBox#groupPlayer4Connected,
138QGroupBox#groupPlayer5Connected,
139QGroupBox#groupPlayer6Connected,
140QGroupBox#groupPlayer7Connected,
141QGroupBox#groupPlayer8Connected {
142 border: 1px solid #828790;
143 border-radius: 3px;
144 padding: 0px;
145 min-height: 98px;
146 max-height: 98px;
147}
148
149QGroupBox#groupPlayer1Connected:unchecked,
150QGroupBox#groupPlayer2Connected:unchecked,
151QGroupBox#groupPlayer3Connected:unchecked,
152QGroupBox#groupPlayer4Connected:unchecked,
153QGroupBox#groupPlayer5Connected:unchecked,
154QGroupBox#groupPlayer6Connected:unchecked,
155QGroupBox#groupPlayer7Connected:unchecked,
156QGroupBox#groupPlayer8Connected:unchecked {
157 border: 1px solid #d9d9d9;
158}
159
160QGroupBox#groupPlayer1Connected::title,
161QGroupBox#groupPlayer2Connected::title,
162QGroupBox#groupPlayer3Connected::title,
163QGroupBox#groupPlayer4Connected::title,
164QGroupBox#groupPlayer5Connected::title,
165QGroupBox#groupPlayer6Connected::title,
166QGroupBox#groupPlayer7Connected::title,
167QGroupBox#groupPlayer8Connected::title {
168 subcontrol-origin: margin;
169 subcontrol-position: top left;
170 padding-left: 0px;
171 padding-right: 0px;
172 padding-top: 1px;
173 margin-left: 0px;
174 margin-right: -4px;
175 margin-bottom: 4px;
176}
177
178QCheckBox#checkboxPlayer1Connected,
179QCheckBox#checkboxPlayer2Connected,
180QCheckBox#checkboxPlayer3Connected,
181QCheckBox#checkboxPlayer4Connected,
182QCheckBox#checkboxPlayer5Connected,
183QCheckBox#checkboxPlayer6Connected,
184QCheckBox#checkboxPlayer7Connected,
185QCheckBox#checkboxPlayer8Connected {
186 spacing: 0px;
187}
188
189QWidget#Player1LEDs QCheckBox,
190QWidget#Player2LEDs QCheckBox,
191QWidget#Player3LEDs QCheckBox,
192QWidget#Player4LEDs QCheckBox,
193QWidget#Player5LEDs QCheckBox,
194QWidget#Player6LEDs QCheckBox,
195QWidget#Player7LEDs QCheckBox,
196QWidget#Player8LEDs QCheckBox {
197 spacing: 0px;
198}
199
200QWidget#Player1LEDs QCheckBox::indicator,
201QWidget#Player2LEDs QCheckBox::indicator,
202QWidget#Player3LEDs QCheckBox::indicator,
203QWidget#Player4LEDs QCheckBox::indicator,
204QWidget#Player5LEDs QCheckBox::indicator,
205QWidget#Player6LEDs QCheckBox::indicator,
206QWidget#Player7LEDs QCheckBox::indicator,
207QWidget#Player8LEDs QCheckBox::indicator {
208 width: 6px;
209 height: 6px;
210 margin-left: 0px;
211}
212
213QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
214QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
215QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
216QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
217QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
218QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
219QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
220QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
221 width: 12px;
222 height: 12px;
223}
224
225QCheckBox#checkboxPlayer1Connected::indicator,
226QCheckBox#checkboxPlayer2Connected::indicator,
227QCheckBox#checkboxPlayer3Connected::indicator,
228QCheckBox#checkboxPlayer4Connected::indicator,
229QCheckBox#checkboxPlayer5Connected::indicator,
230QCheckBox#checkboxPlayer6Connected::indicator,
231QCheckBox#checkboxPlayer7Connected::indicator,
232QCheckBox#checkboxPlayer8Connected::indicator {
233 width: 14px;
234 height: 14px;
235}
236
237QGroupBox#groupPlayer1Connected::indicator,
238QGroupBox#groupPlayer2Connected::indicator,
239QGroupBox#groupPlayer3Connected::indicator,
240QGroupBox#groupPlayer4Connected::indicator,
241QGroupBox#groupPlayer5Connected::indicator,
242QGroupBox#groupPlayer6Connected::indicator,
243QGroupBox#groupPlayer7Connected::indicator,
244QGroupBox#groupPlayer8Connected::indicator {
245 width: 16px;
246 height: 16px;
247}
248
249QWidget#Player1LEDs QCheckBox::indicator:checked,
250QWidget#Player2LEDs QCheckBox::indicator:checked,
251QWidget#Player3LEDs QCheckBox::indicator:checked,
252QWidget#Player4LEDs QCheckBox::indicator:checked,
253QWidget#Player5LEDs QCheckBox::indicator:checked,
254QWidget#Player6LEDs QCheckBox::indicator:checked,
255QWidget#Player7LEDs QCheckBox::indicator:checked,
256QWidget#Player8LEDs QCheckBox::indicator:checked,
257QGroupBox#groupPlayer1Connected::indicator:checked,
258QGroupBox#groupPlayer2Connected::indicator:checked,
259QGroupBox#groupPlayer3Connected::indicator:checked,
260QGroupBox#groupPlayer4Connected::indicator:checked,
261QGroupBox#groupPlayer5Connected::indicator:checked,
262QGroupBox#groupPlayer6Connected::indicator:checked,
263QGroupBox#groupPlayer7Connected::indicator:checked,
264QGroupBox#groupPlayer8Connected::indicator:checked,
265QCheckBox#checkboxPlayer1Connected::indicator:checked,
266QCheckBox#checkboxPlayer2Connected::indicator:checked,
267QCheckBox#checkboxPlayer3Connected::indicator:checked,
268QCheckBox#checkboxPlayer4Connected::indicator:checked,
269QCheckBox#checkboxPlayer5Connected::indicator:checked,
270QCheckBox#checkboxPlayer6Connected::indicator:checked,
271QCheckBox#checkboxPlayer7Connected::indicator:checked,
272QCheckBox#checkboxPlayer8Connected::indicator:checked,
273QGroupBox#groupConnectedController::indicator:checked {
274 border-radius: 2px;
275 border: 1px solid #929192;
276 background: #39ff14;
277 image: none;
278}
279
280QWidget#Player1LEDs QCheckBox::indicator:unchecked,
281QWidget#Player2LEDs QCheckBox::indicator:unchecked,
282QWidget#Player3LEDs QCheckBox::indicator:unchecked,
283QWidget#Player4LEDs QCheckBox::indicator:unchecked,
284QWidget#Player5LEDs QCheckBox::indicator:unchecked,
285QWidget#Player6LEDs QCheckBox::indicator:unchecked,
286QWidget#Player7LEDs QCheckBox::indicator:unchecked,
287QWidget#Player8LEDs QCheckBox::indicator:unchecked,
288QGroupBox#groupPlayer1Connected::indicator:unchecked,
289QGroupBox#groupPlayer2Connected::indicator:unchecked,
290QGroupBox#groupPlayer3Connected::indicator:unchecked,
291QGroupBox#groupPlayer4Connected::indicator:unchecked,
292QGroupBox#groupPlayer5Connected::indicator:unchecked,
293QGroupBox#groupPlayer6Connected::indicator:unchecked,
294QGroupBox#groupPlayer7Connected::indicator:unchecked,
295QGroupBox#groupPlayer8Connected::indicator:unchecked,
296QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
297QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
298QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
299QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
300QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
301QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
302QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
303QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
304QGroupBox#groupConnectedController::indicator:unchecked {
305 border-radius: 2px;
306 border: 1px solid #929192;
307 background: transparent;
308 image: none;
309}
310
311QWidget#controllerPlayer1,
312QWidget#controllerPlayer2,
313QWidget#controllerPlayer3,
314QWidget#controllerPlayer4,
315QWidget#controllerPlayer5,
316QWidget#controllerPlayer6,
317QWidget#controllerPlayer7,
318QWidget#controllerPlayer8 {
319 background: transparent;
320}
321
322QDialog#QtSoftwareKeyboardDialog,
323QStackedWidget#topOSK {
324 background: rgba(51, 51, 51, .9);
325}
326
327
328QDialog#OverlayDialog,
329QStackedWidget#stackedDialog {
330 background: rgba(51, 51, 51, .7);
331}
332
333QWidget#boxOSK,
334QWidget#lineOSK,
335QWidget#richDialog,
336QWidget#lineDialog {
337 background: transparent;
338}
339
340QStackedWidget#bottomOSK,
341QWidget#contentDialog,
342QWidget#contentRichDialog {
343 background: rgba(240, 240, 240, 1);
344}
345
346QWidget#contentDialog,
347QWidget#contentRichDialog {
348 margin: 5px;
349 border-radius: 6px;
350}
351
352QWidget#buttonsDialog,
353QWidget#buttonsRichDialog {
354 margin: 5px;
355 border-top: 2px solid rgba(44, 44, 44, 1);
356}
357
358QWidget#legendOSKnum {
359 border-top: 1px solid rgba(44, 44, 44, 1);
360}
361
362QStackedWidget#stackedDialog QTextBrowser QScrollBar::vertical {
363 background: #cdcdcd;
364 width: 15px;
365 margin: 15px 3px 15px 3px;
366 border: 1px transparent;
367 border-radius: 4px;
368}
369
370QStackedWidget#stackedDialog QTextBrowser QScrollBar::horizoncal {
371 background: #cdcdcd;
372 height: 15px;
373 margin: 3px 15px 3px 15px;
374 border: 1px transparent;
375 border-radius: 4px;
376}
377
378QStackedWidget#stackedDialog QTextBrowser QScrollBar::handle {
379 background: #fff;
380 border-radius: 4px;
381 min-height: 5px;
382 min-width: 5px;
383}
384
385QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line,
386QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
387QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-page,
388QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-page {
389 background: none;
390}
391
392QWidget#inputOSK {
393 border-bottom: 3px solid rgba(255, 255, 255, .9);
394}
395
396QWidget#inputOSK QLineEdit {
397 background: transparent;
398 border: none;
399 color: #ccc;
400}
401
402QWidget#inputBoxOSK {
403 border: 2px solid rgba(255, 255, 255, .9);
404}
405
406QWidget#inputBoxOSK QTextEdit {
407 background: transparent;
408 border: none;
409 color: #ccc;
410}
411
412QWidget#richDialog QTextBrowser {
413 background: transparent;
414 border: none;
415 padding: 35px 65px;
416}
417
418
419QWidget#lineOSK QLabel#label_header {
420 color: #f0f0f0;
421}
422
423QWidget#lineOSK QLabel#label_sub,
424QWidget#lineOSK QLabel#label_characters,
425QWidget#boxOSK QLabel#label_characters_box {
426 color: #ccc;
427}
428
429QWidget#contentDialog QLabel#label_title,
430QWidget#contentRichDialog QLabel#label_title_rich {
431 color: #888;
432}
433
434QWidget#contentDialog QLabel#label_dialog {
435 padding: 20px 65px;
436}
437
438QWidget#contentDialog QLabel#label_title,
439QWidget#contentRichDialog QLabel#label_title_rich {
440 padding: 0px 65px;
441}
442
443QDialog#OverlayDialog QPushButton {
444 color: rgba(49, 79, 239, 1);
445 background: transparent;
446 border: none;
447 padding: 0px;
448 min-width: 0px;
449}
450
451QDialog#OverlayDialog QPushButton:focus,
452QDialog#OverlayDialog QPushButton:hover {
453 color: rgba(49, 79, 239, 1);
454 background: rgba(255, 255, 255, 1);
455 border: 5px solid rgba(148, 250, 202, 1);
456 border-radius: 6px;
457 outline: none;
458}
459
460QDialog#OverlayDialog QPushButton:pressed {
461 color: rgba(240, 240, 240, 1);
462 background: rgba(150, 150, 150, 1);
463 border: 5px solid rgba(148, 250, 202, 1);
464 border-radius: 6px;
465 outline: none;
466}
467
468QDialog#QtSoftwareKeyboardDialog QPushButton {
469 background: rgba(232, 232, 232, 1);
470 border: 2px solid rgba(240, 240, 240, 1);
471}
472
473QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
474QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
475QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
476QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
477QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
478QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
479 background: rgba(218, 218, 218, 1);
480 border: 2px solid rgba(240, 240, 240, 1);
481}
482
483QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
484QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
485QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
486 color: rgba(240, 240, 240, 1);
487 background: rgba(44, 44, 44, 1);
488 border: 2px solid rgba(240, 240, 240, 1);
489}
490
491QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
492QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
493QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
494 color: rgba(240, 240, 240, 1);
495 background: rgba(49, 79, 239, 1);
496 border: 2px solid rgba(240, 240, 240, 1);
497}
498
499QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
500QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
501QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
502QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
503QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
504QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
505QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
506QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
507QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
508QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
509QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
510QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
511QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
512
513QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
514QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
515QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
516QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
517QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
518QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
519QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
520QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
521QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
522QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
523QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
524QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
525QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
526 color: rgba(0, 0, 0, 1);
527 background: rgba(255, 255, 255, 1);
528 border: 5px solid rgba(148, 250, 202, 1);
529 border-radius: 6px;
530 outline: none;
531}
532
533QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
534QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
535QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
536QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
537QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
538QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
539QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
540QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
541QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
542QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
543QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
544QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
545QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
546 color: rgba(240, 240, 240, 1);
547 background: rgba(150, 150, 150, 1);
548 border: 5px solid rgba(148, 250, 202, 1);
549 border-radius: 6px;
550}
551
552QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
553QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
554QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
555 image: url(:/overlay/osk_button_B.png);
556 image-position: right;
557 qproperty-icon: url(:/overlay/osk_button_backspace.png);
558 qproperty-iconSize: 36px;
559}
560
561QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
562QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
563 image: url(:/overlay/osk_button_Y.png);
564 image-position: right;
565}
566
567QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
568QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
569QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
570 image: url(:/overlay/osk_button_plus.png);
571 image-position: right;
572}
573
574QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
575 image: url(:/overlay/osk_button_shift_lock_off.png);
576 image-position: left;
577 qproperty-icon: url(:/overlay/osk_button_shift.png);
578 qproperty-iconSize: 36px;
579}
580
581QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
582 image: url(:/overlay/osk_button_shift_lock_off.png);
583 image-position: left;
584 qproperty-icon: url(:/overlay/osk_button_shift_on.png);
585 qproperty-iconSize: 36px;
586}
587
588QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
589QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
590QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
591QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
592 padding-bottom: 7px;
593}
594
595QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
596 background: transparent;
597 color: #ccc;
598}
599
600QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
601QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
602QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
603 image: url(:/overlay/button_L.png);
604}
605
606QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
607QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
608QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
609 image: url(:/overlay/arrow_left.png);
610}
611
612QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
613QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
614QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
615 image: url(:/overlay/button_R.png);
616}
617
618QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
619QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
620QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
621 image: url(:/overlay/arrow_right.png);
622}
623
624QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
625QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
626 image: url(:/overlay/button_press_stick.png);
627}
628
629QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
630QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
631QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
632 image: url(:/overlay/button_X.png);
633}
634
635QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
636QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
637QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
638 image: url(:/overlay/button_A.png);
639}
640
641QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
642QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
643QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
644QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
645QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
646QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
647QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
648QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
649QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
650QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
651 color: rgba(164, 164, 164, 1);
652 background-color: rgba(218, 218, 218, 1);
653}
654
655QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
656QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
657QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
658QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
659QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
660QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
661QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
662QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
663QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
664QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
665QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
666QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
667QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
668QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
669 color: rgba(164, 164, 164, 1);
670}
671
672QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
673QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
674QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
675 image: url(:/overlay/osk_button_plus_disabled.png);
676}
677
678QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
679QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
680QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
681 image: url(:/overlay/osk_button_B_disabled.png);
682}
683
684QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
685QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
686 image: url(:/overlay/osk_button_Y_disabled.png);
687}
diff --git a/dist/qt_themes/qdarkstyle/icons/16x16/refresh.png b/dist/qt_themes/qdarkstyle/icons/16x16/refresh.png
deleted file mode 100644
index d4afd76f9..000000000
--- a/dist/qt_themes/qdarkstyle/icons/16x16/refresh.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/icons/48x48/plus.png b/dist/qt_themes/qdarkstyle/icons/48x48/list-add.png
index 16cc8b4f4..16cc8b4f4 100644
--- a/dist/qt_themes/qdarkstyle/icons/48x48/plus.png
+++ b/dist/qt_themes/qdarkstyle/icons/48x48/list-add.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/style.qrc b/dist/qt_themes/qdarkstyle/style.qrc
index f770e09fd..a89fb26c6 100644
--- a/dist/qt_themes/qdarkstyle/style.qrc
+++ b/dist/qt_themes/qdarkstyle/style.qrc
@@ -10,7 +10,7 @@
10 <file alias="48x48/chip.png">icons/48x48/chip.png</file> 10 <file alias="48x48/chip.png">icons/48x48/chip.png</file>
11 <file alias="48x48/folder.png">icons/48x48/folder.png</file> 11 <file alias="48x48/folder.png">icons/48x48/folder.png</file>
12 <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file> 12 <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
13 <file alias="48x48/plus.png">icons/48x48/plus.png</file> 13 <file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
14 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> 14 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
15 <file alias="48x48/star.png">icons/48x48/star.png</file> 15 <file alias="48x48/star.png">icons/48x48/star.png</file>
16 <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> 16 <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png
deleted file mode 100644
index c750a39e8..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png
deleted file mode 100644
index d4afd76f9..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png
deleted file mode 100644
index d4afd76f9..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png
deleted file mode 100644
index 303f9a321..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png
deleted file mode 100644
index 4a9709623..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png
deleted file mode 100644
index 973fabd05..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png
deleted file mode 100644
index 0f1e987d6..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png
deleted file mode 100644
index 16cc8b4f4..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png
deleted file mode 100644
index 0291c6542..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png
deleted file mode 100644
index 90d423a1d..000000000
--- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/star.png
+++ /dev/null
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
index 142dd3288..dc3d7fecb 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
@@ -1,15 +1,16 @@
1<RCC> 1<RCC>
2 <qresource prefix="icons/qdarkstyle_midnight_blue"> 2 <qresource prefix="icons/qdarkstyle_midnight_blue">
3 <file alias="index.theme">icons/index.theme</file> 3 <file alias="index.theme">icons/index.theme</file>
4 <file alias="16x16/lock.png">icons/16x16/lock.png</file> 4 <file alias="16x16/lock.png">../qdarkstyle/icons/16x16/lock.png</file>
5 <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file> 5 <file alias="16x16/view-refresh.png">../qdarkstyle/icons/16x16/view-refresh.png</file>
6 <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> 6 <file alias="48x48/bad_folder.png">../qdarkstyle/icons/48x48/bad_folder.png</file>
7 <file alias="48x48/chip.png">icons/48x48/chip.png</file> 7 <file alias="48x48/chip.png">../qdarkstyle/icons/48x48/chip.png</file>
8 <file alias="48x48/folder.png">icons/48x48/folder.png</file> 8 <file alias="48x48/folder.png">../qdarkstyle/icons/48x48/folder.png</file>
9 <file alias="48x48/plus.png">icons/48x48/plus.png</file> 9 <file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
10 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> 10 <file alias="48x48/list-add.png">../qdarkstyle/icons/48x48/list-add.png</file>
11 <file alias="48x48/star.png">icons/48x48/star.png</file> 11 <file alias="48x48/sd_card.png">../qdarkstyle/icons/48x48/sd_card.png</file>
12 <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> 12 <file alias="48x48/star.png">../qdarkstyle/icons/48x48/star.png</file>
13 <file alias="256x256/plus_folder.png">../qdarkstyle/icons/256x256/plus_folder.png</file>
13 </qresource> 14 </qresource>
14 <qresource prefix="qss_icons"> 15 <qresource prefix="qss_icons">
15 <file>rc/arrow_down.png</file> 16 <file>rc/arrow_down.png</file>
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp
index a4e28de6d..90d049e8e 100644
--- a/src/audio_core/sink/cubeb_sink.cpp
+++ b/src/audio_core/sink/cubeb_sink.cpp
@@ -185,6 +185,9 @@ public:
185 constexpr s32 max{std::numeric_limits<s16>::max()}; 185 constexpr s32 max{std::numeric_limits<s16>::max()};
186 186
187 auto yuzu_volume{Settings::Volume()}; 187 auto yuzu_volume{Settings::Volume()};
188 if (yuzu_volume > 1.0f) {
189 yuzu_volume = 0.6f + 20 * std::log10(yuzu_volume);
190 }
188 auto volume{system_volume * device_volume * yuzu_volume}; 191 auto volume{system_volume * device_volume * yuzu_volume};
189 192
190 if (system_channels == 6 && device_channels == 2) { 193 if (system_channels == 6 && device_channels == 2) {
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 1c7b6dfae..7282a45d3 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -105,7 +105,7 @@ float Volume() {
105 if (values.audio_muted) { 105 if (values.audio_muted) {
106 return 0.0f; 106 return 0.0f;
107 } 107 }
108 return values.volume.GetValue() / 100.0f; 108 return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault());
109} 109}
110 110
111void UpdateRescalingInfo() { 111void UpdateRescalingInfo() {
diff --git a/src/common/settings.h b/src/common/settings.h
index 1079cf8cb..14ed9b237 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -374,7 +374,7 @@ struct Values {
374 Setting<std::string> audio_output_device_id{"auto", "output_device"}; 374 Setting<std::string> audio_output_device_id{"auto", "output_device"};
375 Setting<std::string> audio_input_device_id{"auto", "input_device"}; 375 Setting<std::string> audio_input_device_id{"auto", "input_device"};
376 Setting<bool> audio_muted{false, "audio_muted"}; 376 Setting<bool> audio_muted{false, "audio_muted"};
377 SwitchableSetting<u8, true> volume{100, 0, 100, "volume"}; 377 SwitchableSetting<u8, true> volume{100, 0, 200, "volume"};
378 Setting<bool> dump_audio_commands{false, "dump_audio_commands"}; 378 Setting<bool> dump_audio_commands{false, "dump_audio_commands"};
379 379
380 // Core 380 // Core
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 052357be4..4e39649a8 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -502,9 +502,10 @@ add_library(core STATIC
502 hle/service/jit/jit.h 502 hle/service/jit/jit.h
503 hle/service/lbl/lbl.cpp 503 hle/service/lbl/lbl.cpp
504 hle/service/lbl/lbl.h 504 hle/service/lbl/lbl.h
505 hle/service/ldn/errors.h 505 hle/service/ldn/ldn_results.h
506 hle/service/ldn/ldn.cpp 506 hle/service/ldn/ldn.cpp
507 hle/service/ldn/ldn.h 507 hle/service/ldn/ldn.h
508 hle/service/ldn/ldn_types.h
508 hle/service/ldr/ldr.cpp 509 hle/service/ldr/ldr.cpp
509 hle/service/ldr/ldr.h 510 hle/service/ldr/ldr.h
510 hle/service/lm/lm.cpp 511 hle/service/lm/lm.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 1638bc41d..3b8b43994 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -195,14 +195,16 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
195 if (page_table) { 195 if (page_table) {
196 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 196 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
197 page_table->pointers.data()); 197 page_table->pointers.data());
198 config.absolute_offset_page_table = true;
199 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
200 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
201 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
202
198 config.fastmem_pointer = page_table->fastmem_arena; 203 config.fastmem_pointer = page_table->fastmem_arena;
204
205 config.fastmem_exclusive_access = config.fastmem_pointer != nullptr;
206 config.recompile_on_exclusive_fastmem_failure = true;
199 } 207 }
200 config.absolute_offset_page_table = true;
201 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
202 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
203 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
204 config.fastmem_exclusive_access = true;
205 config.recompile_on_exclusive_fastmem_failure = true;
206 208
207 // Multi-process state 209 // Multi-process state
208 config.processor_id = core_index; 210 config.processor_id = core_index;
@@ -254,6 +256,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
254 } 256 }
255 if (!Settings::values.cpuopt_fastmem) { 257 if (!Settings::values.cpuopt_fastmem) {
256 config.fastmem_pointer = nullptr; 258 config.fastmem_pointer = nullptr;
259 config.fastmem_exclusive_access = false;
257 } 260 }
258 if (!Settings::values.cpuopt_fastmem_exclusives) { 261 if (!Settings::values.cpuopt_fastmem_exclusives) {
259 config.fastmem_exclusive_access = false; 262 config.fastmem_exclusive_access = false;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 921a5a734..1d46f6d40 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -250,7 +250,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
250 config.fastmem_address_space_bits = address_space_bits; 250 config.fastmem_address_space_bits = address_space_bits;
251 config.silently_mirror_fastmem = false; 251 config.silently_mirror_fastmem = false;
252 252
253 config.fastmem_exclusive_access = true; 253 config.fastmem_exclusive_access = config.fastmem_pointer != nullptr;
254 config.recompile_on_exclusive_fastmem_failure = true; 254 config.recompile_on_exclusive_fastmem_failure = true;
255 } 255 }
256 256
@@ -314,6 +314,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
314 } 314 }
315 if (!Settings::values.cpuopt_fastmem) { 315 if (!Settings::values.cpuopt_fastmem) {
316 config.fastmem_pointer = nullptr; 316 config.fastmem_pointer = nullptr;
317 config.fastmem_exclusive_access = false;
317 } 318 }
318 if (!Settings::values.cpuopt_fastmem_exclusives) { 319 if (!Settings::values.cpuopt_fastmem_exclusives) {
319 config.fastmem_exclusive_access = false; 320 config.fastmem_exclusive_access = false;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index e9123c13d..200efe4db 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -8,6 +8,10 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10 10
11#ifdef _MSC_VER
12#include <intrin.h>
13#endif
14
11using Callback = Dynarmic::A32::Coprocessor::Callback; 15using Callback = Dynarmic::A32::Coprocessor::Callback;
12using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; 16using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
13using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; 17using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
@@ -47,12 +51,31 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
47 switch (opc2) { 51 switch (opc2) {
48 case 4: 52 case 4:
49 // CP15_DATA_SYNC_BARRIER 53 // CP15_DATA_SYNC_BARRIER
50 // This is a dummy write, we ignore the value written here. 54 return Callback{
51 return &dummy_value; 55 [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
56#ifdef _MSC_VER
57 _mm_mfence();
58 _mm_lfence();
59#else
60 asm volatile("mfence\n\tlfence\n\t" : : : "memory");
61#endif
62 return 0;
63 },
64 std::nullopt,
65 };
52 case 5: 66 case 5:
53 // CP15_DATA_MEMORY_BARRIER 67 // CP15_DATA_MEMORY_BARRIER
54 // This is a dummy write, we ignore the value written here. 68 return Callback{
55 return &dummy_value; 69 [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
70#ifdef _MSC_VER
71 _mm_mfence();
72#else
73 asm volatile("mfence\n\t" : : : "memory");
74#endif
75 return 0;
76 },
77 std::nullopt,
78 };
56 } 79 }
57 } 80 }
58 81
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 5b2a51636..d90b3e568 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -35,6 +35,8 @@ public:
35 ARM_Dynarmic_32& parent; 35 ARM_Dynarmic_32& parent;
36 u32 uprw = 0; 36 u32 uprw = 0;
37 u32 uro = 0; 37 u32 uro = 0;
38
39 friend class ARM_Dynarmic_32;
38}; 40};
39 41
40} // namespace Core 42} // namespace Core
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 4b35ca82f..a33dbe94b 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -287,7 +287,8 @@ void IPSwitchCompiler::Parse() {
287 std::copy(value.begin(), value.end(), std::back_inserter(replace)); 287 std::copy(value.begin(), value.end(), std::back_inserter(replace));
288 } else { 288 } else {
289 // hex replacement 289 // hex replacement
290 const auto value = patch_line.substr(9); 290 const auto value =
291 patch_line.substr(9, patch_line.find_first_of(" /\r\n", 9) - 9);
291 replace = Common::HexStringToVector(value, is_little_endian); 292 replace = Common::HexStringToVector(value, is_little_endian);
292 } 293 }
293 294
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 8c3895937..049602e7d 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/thread.h"
4#include "core/hid/emulated_controller.h" 5#include "core/hid/emulated_controller.h"
5#include "core/hid/input_converter.h" 6#include "core/hid/input_converter.h"
6 7
@@ -84,18 +85,19 @@ void EmulatedController::ReloadFromSettings() {
84 motion_params[index] = Common::ParamPackage(player.motions[index]); 85 motion_params[index] = Common::ParamPackage(player.motions[index]);
85 } 86 }
86 87
88 controller.colors_state.fullkey = {
89 .body = GetNpadColor(player.body_color_left),
90 .button = GetNpadColor(player.button_color_left),
91 };
87 controller.colors_state.left = { 92 controller.colors_state.left = {
88 .body = player.body_color_left, 93 .body = GetNpadColor(player.body_color_left),
89 .button = player.button_color_left, 94 .button = GetNpadColor(player.button_color_left),
90 }; 95 };
91 96 controller.colors_state.left = {
92 controller.colors_state.right = { 97 .body = GetNpadColor(player.body_color_right),
93 .body = player.body_color_right, 98 .button = GetNpadColor(player.button_color_right),
94 .button = player.button_color_right,
95 }; 99 };
96 100
97 controller.colors_state.fullkey = controller.colors_state.left;
98
99 // Other or debug controller should always be a pro controller 101 // Other or debug controller should always be a pro controller
100 if (npad_id_type != NpadIdType::Other) { 102 if (npad_id_type != NpadIdType::Other) {
101 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); 103 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
@@ -949,6 +951,9 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
949 // Send a slight vibration to test for rumble support 951 // Send a slight vibration to test for rumble support
950 output_devices[device_index]->SetVibration(test_vibration); 952 output_devices[device_index]->SetVibration(test_vibration);
951 953
954 // Wait for about 15ms to ensure the controller is ready for the stop command
955 std::this_thread::sleep_for(std::chrono::milliseconds(15));
956
952 // Stop any vibration and return the result 957 // Stop any vibration and return the result
953 return output_devices[device_index]->SetVibration(zero_vibration) == 958 return output_devices[device_index]->SetVibration(zero_vibration) ==
954 Common::Input::VibrationError::None; 959 Common::Input::VibrationError::None;
@@ -1310,6 +1315,15 @@ const CameraState& EmulatedController::GetCamera() const {
1310 return controller.camera_state; 1315 return controller.camera_state;
1311} 1316}
1312 1317
1318NpadColor EmulatedController::GetNpadColor(u32 color) {
1319 return {
1320 .r = static_cast<u8>((color >> 16) & 0xFF),
1321 .g = static_cast<u8>((color >> 8) & 0xFF),
1322 .b = static_cast<u8>(color & 0xFF),
1323 .a = 0xff,
1324 };
1325}
1326
1313void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { 1327void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
1314 std::scoped_lock lock{callback_mutex}; 1328 std::scoped_lock lock{callback_mutex};
1315 for (const auto& poller_pair : callback_list) { 1329 for (const auto& poller_pair : callback_list) {
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 823c1700c..cbd7c26d3 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -425,6 +425,13 @@ private:
425 void SetCamera(const Common::Input::CallbackStatus& callback); 425 void SetCamera(const Common::Input::CallbackStatus& callback);
426 426
427 /** 427 /**
428 * Converts a color format from bgra to rgba
429 * @param color in bgra format
430 * @return NpadColor in rgba format
431 */
432 NpadColor GetNpadColor(u32 color);
433
434 /**
428 * Triggers a callback that something has changed on the controller status 435 * Triggers a callback that something has changed on the controller status
429 * @param type Input type of the event to trigger 436 * @param type Input type of the event to trigger
430 * @param is_service_update indicates if this event should only be sent to HID services 437 * @param is_service_update indicates if this event should only be sent to HID services
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index e49223016..e3b1cfbc6 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -327,10 +327,18 @@ struct TouchState {
327}; 327};
328static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); 328static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
329 329
330struct NpadColor {
331 u8 r{};
332 u8 g{};
333 u8 b{};
334 u8 a{};
335};
336static_assert(sizeof(NpadColor) == 4, "NpadColor is an invalid size");
337
330// This is nn::hid::NpadControllerColor 338// This is nn::hid::NpadControllerColor
331struct NpadControllerColor { 339struct NpadControllerColor {
332 u32 body{}; 340 NpadColor body{};
333 u32 button{}; 341 NpadColor button{};
334}; 342};
335static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); 343static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
336 344
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 3c28dee76..cb29004e8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
163 } 163 }
164 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); 164 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
165 const auto controller_type = controller.device->GetNpadStyleIndex(); 165 const auto controller_type = controller.device->GetNpadStyleIndex();
166 const auto& body_colors = controller.device->GetColors();
167 const auto& battery_level = controller.device->GetBattery();
166 auto* shared_memory = controller.shared_memory; 168 auto* shared_memory = controller.shared_memory;
167 if (controller_type == Core::HID::NpadStyleIndex::None) { 169 if (controller_type == Core::HID::NpadStyleIndex::None) {
168 controller.styleset_changed_event->GetWritableEvent().Signal(); 170 controller.styleset_changed_event->GetWritableEvent().Signal();
169 return; 171 return;
170 } 172 }
173
174 // Reset memory values
171 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; 175 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
172 shared_memory->device_type.raw = 0; 176 shared_memory->device_type.raw = 0;
173 shared_memory->system_properties.raw = 0; 177 shared_memory->system_properties.raw = 0;
178 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
179 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
180 shared_memory->fullkey_color = {};
181 shared_memory->joycon_color.left = {};
182 shared_memory->joycon_color.right = {};
183 shared_memory->battery_level_dual = {};
184 shared_memory->battery_level_left = {};
185 shared_memory->battery_level_right = {};
186
174 switch (controller_type) { 187 switch (controller_type) {
175 case Core::HID::NpadStyleIndex::None: 188 case Core::HID::NpadStyleIndex::None:
176 ASSERT(false); 189 ASSERT(false);
177 break; 190 break;
178 case Core::HID::NpadStyleIndex::ProController: 191 case Core::HID::NpadStyleIndex::ProController:
192 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
193 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
194 shared_memory->battery_level_dual = battery_level.dual.battery_level;
179 shared_memory->style_tag.fullkey.Assign(1); 195 shared_memory->style_tag.fullkey.Assign(1);
180 shared_memory->device_type.fullkey.Assign(1); 196 shared_memory->device_type.fullkey.Assign(1);
181 shared_memory->system_properties.is_vertical.Assign(1); 197 shared_memory->system_properties.is_vertical.Assign(1);
182 shared_memory->system_properties.use_plus.Assign(1); 198 shared_memory->system_properties.use_plus.Assign(1);
183 shared_memory->system_properties.use_minus.Assign(1); 199 shared_memory->system_properties.use_minus.Assign(1);
200 shared_memory->system_properties.is_charging_joy_dual.Assign(
201 battery_level.dual.is_charging);
184 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; 202 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
185 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); 203 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
186 break; 204 break;
187 case Core::HID::NpadStyleIndex::Handheld: 205 case Core::HID::NpadStyleIndex::Handheld:
206 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
207 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
208 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
209 shared_memory->joycon_color.left = body_colors.left;
210 shared_memory->joycon_color.right = body_colors.right;
188 shared_memory->style_tag.handheld.Assign(1); 211 shared_memory->style_tag.handheld.Assign(1);
189 shared_memory->device_type.handheld_left.Assign(1); 212 shared_memory->device_type.handheld_left.Assign(1);
190 shared_memory->device_type.handheld_right.Assign(1); 213 shared_memory->device_type.handheld_right.Assign(1);
@@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
192 shared_memory->system_properties.use_plus.Assign(1); 215 shared_memory->system_properties.use_plus.Assign(1);
193 shared_memory->system_properties.use_minus.Assign(1); 216 shared_memory->system_properties.use_minus.Assign(1);
194 shared_memory->system_properties.use_directional_buttons.Assign(1); 217 shared_memory->system_properties.use_directional_buttons.Assign(1);
218 shared_memory->system_properties.is_charging_joy_dual.Assign(
219 battery_level.left.is_charging);
220 shared_memory->system_properties.is_charging_joy_left.Assign(
221 battery_level.left.is_charging);
222 shared_memory->system_properties.is_charging_joy_right.Assign(
223 battery_level.right.is_charging);
195 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; 224 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
196 shared_memory->applet_nfc_xcd.applet_footer.type = 225 shared_memory->applet_nfc_xcd.applet_footer.type =
197 AppletFooterUiType::HandheldJoyConLeftJoyConRight; 226 AppletFooterUiType::HandheldJoyConLeftJoyConRight;
198 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); 227 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
199 break; 228 break;
200 case Core::HID::NpadStyleIndex::JoyconDual: 229 case Core::HID::NpadStyleIndex::JoyconDual:
230 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
231 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
201 shared_memory->style_tag.joycon_dual.Assign(1); 232 shared_memory->style_tag.joycon_dual.Assign(1);
202 if (controller.is_dual_left_connected) { 233 if (controller.is_dual_left_connected) {
234 shared_memory->joycon_color.left = body_colors.left;
235 shared_memory->battery_level_left = battery_level.left.battery_level;
203 shared_memory->device_type.joycon_left.Assign(1); 236 shared_memory->device_type.joycon_left.Assign(1);
204 shared_memory->system_properties.use_minus.Assign(1); 237 shared_memory->system_properties.use_minus.Assign(1);
238 shared_memory->system_properties.is_charging_joy_left.Assign(
239 battery_level.left.is_charging);
205 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); 240 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
206 } 241 }
207 if (controller.is_dual_right_connected) { 242 if (controller.is_dual_right_connected) {
243 shared_memory->joycon_color.right = body_colors.right;
244 shared_memory->battery_level_right = battery_level.right.battery_level;
208 shared_memory->device_type.joycon_right.Assign(1); 245 shared_memory->device_type.joycon_right.Assign(1);
209 shared_memory->system_properties.use_plus.Assign(1); 246 shared_memory->system_properties.use_plus.Assign(1);
247 shared_memory->system_properties.is_charging_joy_right.Assign(
248 battery_level.right.is_charging);
210 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); 249 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
211 } 250 }
212 shared_memory->system_properties.use_directional_buttons.Assign(1); 251 shared_memory->system_properties.use_directional_buttons.Assign(1);
213 shared_memory->system_properties.is_vertical.Assign(1); 252 shared_memory->system_properties.is_vertical.Assign(1);
214 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; 253 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
254
215 if (controller.is_dual_left_connected && controller.is_dual_right_connected) { 255 if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
216 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; 256 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
257 shared_memory->fullkey_color.fullkey = body_colors.left;
258 shared_memory->battery_level_dual = battery_level.left.battery_level;
259 shared_memory->system_properties.is_charging_joy_dual.Assign(
260 battery_level.left.is_charging);
217 } else if (controller.is_dual_left_connected) { 261 } else if (controller.is_dual_left_connected) {
218 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; 262 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
263 shared_memory->fullkey_color.fullkey = body_colors.left;
264 shared_memory->battery_level_dual = battery_level.left.battery_level;
265 shared_memory->system_properties.is_charging_joy_dual.Assign(
266 battery_level.left.is_charging);
219 } else { 267 } else {
220 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; 268 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
269 shared_memory->fullkey_color.fullkey = body_colors.right;
270 shared_memory->battery_level_dual = battery_level.right.battery_level;
271 shared_memory->system_properties.is_charging_joy_dual.Assign(
272 battery_level.right.is_charging);
221 } 273 }
222 break; 274 break;
223 case Core::HID::NpadStyleIndex::JoyconLeft: 275 case Core::HID::NpadStyleIndex::JoyconLeft:
276 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
277 shared_memory->joycon_color.left = body_colors.left;
278 shared_memory->battery_level_dual = battery_level.left.battery_level;
224 shared_memory->style_tag.joycon_left.Assign(1); 279 shared_memory->style_tag.joycon_left.Assign(1);
225 shared_memory->device_type.joycon_left.Assign(1); 280 shared_memory->device_type.joycon_left.Assign(1);
226 shared_memory->system_properties.is_horizontal.Assign(1); 281 shared_memory->system_properties.is_horizontal.Assign(1);
227 shared_memory->system_properties.use_minus.Assign(1); 282 shared_memory->system_properties.use_minus.Assign(1);
283 shared_memory->system_properties.is_charging_joy_left.Assign(
284 battery_level.left.is_charging);
228 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; 285 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
229 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); 286 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
230 break; 287 break;
231 case Core::HID::NpadStyleIndex::JoyconRight: 288 case Core::HID::NpadStyleIndex::JoyconRight:
289 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
290 shared_memory->joycon_color.right = body_colors.right;
291 shared_memory->battery_level_right = battery_level.right.battery_level;
232 shared_memory->style_tag.joycon_right.Assign(1); 292 shared_memory->style_tag.joycon_right.Assign(1);
233 shared_memory->device_type.joycon_right.Assign(1); 293 shared_memory->device_type.joycon_right.Assign(1);
234 shared_memory->system_properties.is_horizontal.Assign(1); 294 shared_memory->system_properties.is_horizontal.Assign(1);
235 shared_memory->system_properties.use_plus.Assign(1); 295 shared_memory->system_properties.use_plus.Assign(1);
296 shared_memory->system_properties.is_charging_joy_right.Assign(
297 battery_level.right.is_charging);
236 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; 298 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
237 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); 299 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
238 break; 300 break;
@@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
269 break; 331 break;
270 } 332 }
271 333
272 const auto& body_colors = controller.device->GetColors();
273
274 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
275 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
276
277 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
278 shared_memory->joycon_color.left = body_colors.left;
279 shared_memory->joycon_color.right = body_colors.right;
280
281 // TODO: Investigate when we should report all batery types
282 const auto& battery_level = controller.device->GetBattery();
283 shared_memory->battery_level_dual = battery_level.dual.battery_level;
284 shared_memory->battery_level_left = battery_level.left.battery_level;
285 shared_memory->battery_level_right = battery_level.right.battery_level;
286
287 controller.is_connected = true; 334 controller.is_connected = true;
288 controller.device->Connect(); 335 controller.device->Connect();
289 SignalStyleSetChangedEvent(npad_id); 336 SignalStyleSetChangedEvent(npad_id);
diff --git a/src/core/hle/service/ldn/errors.h b/src/core/hle/service/ldn/errors.h
deleted file mode 100644
index 972a74806..000000000
--- a/src/core/hle/service/ldn/errors.h
+++ /dev/null
@@ -1,12 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::LDN {
9
10constexpr Result ERROR_DISABLED{ErrorModule::LDN, 22};
11
12} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 125d4dc4c..c11daff54 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -3,11 +3,15 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "core/hle/ipc_helpers.h" 6#include "core/core.h"
7#include "core/hle/result.h"
8#include "core/hle/service/ldn/errors.h"
9#include "core/hle/service/ldn/ldn.h" 7#include "core/hle/service/ldn/ldn.h"
10#include "core/hle/service/sm/sm.h" 8#include "core/hle/service/ldn/ldn_results.h"
9#include "core/hle/service/ldn/ldn_types.h"
10#include "core/internal_network/network.h"
11#include "core/internal_network/network_interface.h"
12
13// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
14#undef CreateEvent
11 15
12namespace Service::LDN { 16namespace Service::LDN {
13 17
@@ -100,74 +104,418 @@ class IUserLocalCommunicationService final
100 : public ServiceFramework<IUserLocalCommunicationService> { 104 : public ServiceFramework<IUserLocalCommunicationService> {
101public: 105public:
102 explicit IUserLocalCommunicationService(Core::System& system_) 106 explicit IUserLocalCommunicationService(Core::System& system_)
103 : ServiceFramework{system_, "IUserLocalCommunicationService"} { 107 : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew},
108 service_context{system, "IUserLocalCommunicationService"}, room_network{
109 system_.GetRoomNetwork()} {
104 // clang-format off 110 // clang-format off
105 static const FunctionInfo functions[] = { 111 static const FunctionInfo functions[] = {
106 {0, &IUserLocalCommunicationService::GetState, "GetState"}, 112 {0, &IUserLocalCommunicationService::GetState, "GetState"},
107 {1, nullptr, "GetNetworkInfo"}, 113 {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
108 {2, nullptr, "GetIpv4Address"}, 114 {2, nullptr, "GetIpv4Address"},
109 {3, nullptr, "GetDisconnectReason"}, 115 {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
110 {4, nullptr, "GetSecurityParameter"}, 116 {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
111 {5, nullptr, "GetNetworkConfig"}, 117 {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
112 {100, nullptr, "AttachStateChangeEvent"}, 118 {100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
113 {101, nullptr, "GetNetworkInfoLatestUpdate"}, 119 {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
114 {102, nullptr, "Scan"}, 120 {102, &IUserLocalCommunicationService::Scan, "Scan"},
115 {103, nullptr, "ScanPrivate"}, 121 {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
116 {104, nullptr, "SetWirelessControllerRestriction"}, 122 {104, nullptr, "SetWirelessControllerRestriction"},
117 {200, nullptr, "OpenAccessPoint"}, 123 {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
118 {201, nullptr, "CloseAccessPoint"}, 124 {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
119 {202, nullptr, "CreateNetwork"}, 125 {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
120 {203, nullptr, "CreateNetworkPrivate"}, 126 {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
121 {204, nullptr, "DestroyNetwork"}, 127 {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
122 {205, nullptr, "Reject"}, 128 {205, nullptr, "Reject"},
123 {206, nullptr, "SetAdvertiseData"}, 129 {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
124 {207, nullptr, "SetStationAcceptPolicy"}, 130 {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
125 {208, nullptr, "AddAcceptFilterEntry"}, 131 {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
126 {209, nullptr, "ClearAcceptFilter"}, 132 {209, nullptr, "ClearAcceptFilter"},
127 {300, nullptr, "OpenStation"}, 133 {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
128 {301, nullptr, "CloseStation"}, 134 {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
129 {302, nullptr, "Connect"}, 135 {302, &IUserLocalCommunicationService::Connect, "Connect"},
130 {303, nullptr, "ConnectPrivate"}, 136 {303, nullptr, "ConnectPrivate"},
131 {304, nullptr, "Disconnect"}, 137 {304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
132 {400, nullptr, "Initialize"}, 138 {400, &IUserLocalCommunicationService::Initialize, "Initialize"},
133 {401, nullptr, "Finalize"}, 139 {401, &IUserLocalCommunicationService::Finalize, "Finalize"},
134 {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+ 140 {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
135 }; 141 };
136 // clang-format on 142 // clang-format on
137 143
138 RegisterHandlers(functions); 144 RegisterHandlers(functions);
145
146 state_change_event =
147 service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
148 }
149
150 ~IUserLocalCommunicationService() {
151 service_context.CloseEvent(state_change_event);
152 }
153
154 void OnEventFired() {
155 state_change_event->GetWritableEvent().Signal();
139 } 156 }
140 157
141 void GetState(Kernel::HLERequestContext& ctx) { 158 void GetState(Kernel::HLERequestContext& ctx) {
159 State state = State::Error;
160 LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state);
161
162 IPC::ResponseBuilder rb{ctx, 3};
163 rb.Push(ResultSuccess);
164 rb.PushEnum(state);
165 }
166
167 void GetNetworkInfo(Kernel::HLERequestContext& ctx) {
168 const auto write_buffer_size = ctx.GetWriteBufferSize();
169
170 if (write_buffer_size != sizeof(NetworkInfo)) {
171 LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
172 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(ResultBadInput);
174 return;
175 }
176
177 NetworkInfo network_info{};
178 const auto rc = ResultSuccess;
179 if (rc.IsError()) {
180 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(rc);
183 return;
184 }
185
186 LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
187 network_info.common.ssid.GetStringValue(), network_info.ldn.node_count);
188
189 ctx.WriteBuffer<NetworkInfo>(network_info);
190 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(rc);
192 }
193
194 void GetDisconnectReason(Kernel::HLERequestContext& ctx) {
195 const auto disconnect_reason = DisconnectReason::None;
196
197 LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason);
198
199 IPC::ResponseBuilder rb{ctx, 3};
200 rb.Push(ResultSuccess);
201 rb.PushEnum(disconnect_reason);
202 }
203
204 void GetSecurityParameter(Kernel::HLERequestContext& ctx) {
205 SecurityParameter security_parameter{};
206 NetworkInfo info{};
207 const Result rc = ResultSuccess;
208
209 if (rc.IsError()) {
210 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
211 IPC::ResponseBuilder rb{ctx, 2};
212 rb.Push(rc);
213 return;
214 }
215
216 security_parameter.session_id = info.network_id.session_id;
217 std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
218 sizeof(SecurityParameter::data));
219
142 LOG_WARNING(Service_LDN, "(STUBBED) called"); 220 LOG_WARNING(Service_LDN, "(STUBBED) called");
143 221
222 IPC::ResponseBuilder rb{ctx, 10};
223 rb.Push(rc);
224 rb.PushRaw<SecurityParameter>(security_parameter);
225 }
226
227 void GetNetworkConfig(Kernel::HLERequestContext& ctx) {
228 NetworkConfig config{};
229 NetworkInfo info{};
230 const Result rc = ResultSuccess;
231
232 if (rc.IsError()) {
233 LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
234 IPC::ResponseBuilder rb{ctx, 2};
235 rb.Push(rc);
236 return;
237 }
238
239 config.intent_id = info.network_id.intent_id;
240 config.channel = info.common.channel;
241 config.node_count_max = info.ldn.node_count_max;
242 config.local_communication_version = info.ldn.nodes[0].local_communication_version;
243
244 LOG_WARNING(Service_LDN,
245 "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, "
246 "local_communication_version={}",
247 config.intent_id.local_communication_id, config.intent_id.scene_id,
248 config.channel, config.node_count_max, config.local_communication_version);
249
250 IPC::ResponseBuilder rb{ctx, 10};
251 rb.Push(rc);
252 rb.PushRaw<NetworkConfig>(config);
253 }
254
255 void AttachStateChangeEvent(Kernel::HLERequestContext& ctx) {
256 LOG_INFO(Service_LDN, "called");
257
258 IPC::ResponseBuilder rb{ctx, 2, 1};
259 rb.Push(ResultSuccess);
260 rb.PushCopyObjects(state_change_event->GetReadableEvent());
261 }
262
263 void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) {
264 const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
265 const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate);
266
267 if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
268 LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size,
269 node_buffer_count);
270 IPC::ResponseBuilder rb{ctx, 2};
271 rb.Push(ResultBadInput);
272 return;
273 }
274
275 NetworkInfo info;
276 std::vector<NodeLatestUpdate> latest_update(node_buffer_count);
277
278 const auto rc = ResultSuccess;
279 if (rc.IsError()) {
280 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
281 IPC::ResponseBuilder rb{ctx, 2};
282 rb.Push(rc);
283 return;
284 }
285
286 LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
287 info.common.ssid.GetStringValue(), info.ldn.node_count);
288
289 ctx.WriteBuffer(info, 0);
290 ctx.WriteBuffer(latest_update, 1);
291
292 IPC::ResponseBuilder rb{ctx, 2};
293 rb.Push(ResultSuccess);
294 }
295
296 void Scan(Kernel::HLERequestContext& ctx) {
297 ScanImpl(ctx);
298 }
299
300 void ScanPrivate(Kernel::HLERequestContext& ctx) {
301 ScanImpl(ctx, true);
302 }
303
304 void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false) {
305 IPC::RequestParser rp{ctx};
306 const auto channel{rp.PopEnum<WifiChannel>()};
307 const auto scan_filter{rp.PopRaw<ScanFilter>()};
308
309 const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo);
310
311 if (network_info_size == 0) {
312 LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
313 IPC::ResponseBuilder rb{ctx, 2};
314 rb.Push(ResultBadInput);
315 return;
316 }
317
318 u16 count = 0;
319 std::vector<NetworkInfo> network_infos(network_info_size);
320
321 LOG_WARNING(Service_LDN,
322 "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}",
323 channel, scan_filter.flag, scan_filter.network_type);
324
325 ctx.WriteBuffer(network_infos);
326
144 IPC::ResponseBuilder rb{ctx, 3}; 327 IPC::ResponseBuilder rb{ctx, 3};
328 rb.Push(ResultSuccess);
329 rb.Push<u32>(count);
330 }
331
332 void OpenAccessPoint(Kernel::HLERequestContext& ctx) {
333 LOG_WARNING(Service_LDN, "(STUBBED) called");
334
335 IPC::ResponseBuilder rb{ctx, 2};
336 rb.Push(ResultSuccess);
337 }
338
339 void CloseAccessPoint(Kernel::HLERequestContext& ctx) {
340 LOG_WARNING(Service_LDN, "(STUBBED) called");
341
342 IPC::ResponseBuilder rb{ctx, 2};
343 rb.Push(ResultSuccess);
344 }
345
346 void CreateNetwork(Kernel::HLERequestContext& ctx) {
347 IPC::RequestParser rp{ctx};
348 struct Parameters {
349 SecurityConfig security_config;
350 UserConfig user_config;
351 INSERT_PADDING_WORDS_NOINIT(1);
352 NetworkConfig network_config;
353 };
354 static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size.");
355
356 const auto parameters{rp.PopRaw<Parameters>()};
357
358 LOG_WARNING(Service_LDN,
359 "(STUBBED) called, passphrase_size={}, security_mode={}, "
360 "local_communication_version={}",
361 parameters.security_config.passphrase_size,
362 parameters.security_config.security_mode,
363 parameters.network_config.local_communication_version);
364
365 IPC::ResponseBuilder rb{ctx, 2};
366 rb.Push(ResultSuccess);
367 }
368
369 void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) {
370 IPC::RequestParser rp{ctx};
371 struct Parameters {
372 SecurityConfig security_config;
373 SecurityParameter security_parameter;
374 UserConfig user_config;
375 NetworkConfig network_config;
376 };
377 static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size.");
378
379 const auto parameters{rp.PopRaw<Parameters>()};
380
381 LOG_WARNING(Service_LDN,
382 "(STUBBED) called, passphrase_size={}, security_mode={}, "
383 "local_communication_version={}",
384 parameters.security_config.passphrase_size,
385 parameters.security_config.security_mode,
386 parameters.network_config.local_communication_version);
387
388 IPC::ResponseBuilder rb{ctx, 2};
389 rb.Push(ResultSuccess);
390 }
391
392 void DestroyNetwork(Kernel::HLERequestContext& ctx) {
393 LOG_WARNING(Service_LDN, "(STUBBED) called");
394
395 IPC::ResponseBuilder rb{ctx, 2};
396 rb.Push(ResultSuccess);
397 }
398
399 void SetAdvertiseData(Kernel::HLERequestContext& ctx) {
400 std::vector<u8> read_buffer = ctx.ReadBuffer();
401
402 LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size());
403
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(ResultSuccess);
406 }
407
408 void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) {
409 LOG_WARNING(Service_LDN, "(STUBBED) called");
410
411 IPC::ResponseBuilder rb{ctx, 2};
412 rb.Push(ResultSuccess);
413 }
145 414
146 // Indicate a network error, as we do not actually emulate LDN 415 void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) {
147 rb.Push(static_cast<u32>(State::Error)); 416 LOG_WARNING(Service_LDN, "(STUBBED) called");
148 417
418 IPC::ResponseBuilder rb{ctx, 2};
419 rb.Push(ResultSuccess);
420 }
421
422 void OpenStation(Kernel::HLERequestContext& ctx) {
423 LOG_WARNING(Service_LDN, "(STUBBED) called");
424
425 IPC::ResponseBuilder rb{ctx, 2};
426 rb.Push(ResultSuccess);
427 }
428
429 void CloseStation(Kernel::HLERequestContext& ctx) {
430 LOG_WARNING(Service_LDN, "(STUBBED) called");
431
432 IPC::ResponseBuilder rb{ctx, 2};
433 rb.Push(ResultSuccess);
434 }
435
436 void Connect(Kernel::HLERequestContext& ctx) {
437 IPC::RequestParser rp{ctx};
438 struct Parameters {
439 SecurityConfig security_config;
440 UserConfig user_config;
441 u32 local_communication_version;
442 u32 option;
443 };
444 static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size.");
445
446 const auto parameters{rp.PopRaw<Parameters>()};
447
448 LOG_WARNING(Service_LDN,
449 "(STUBBED) called, passphrase_size={}, security_mode={}, "
450 "local_communication_version={}",
451 parameters.security_config.passphrase_size,
452 parameters.security_config.security_mode,
453 parameters.local_communication_version);
454
455 const std::vector<u8> read_buffer = ctx.ReadBuffer();
456 NetworkInfo network_info{};
457
458 if (read_buffer.size() != sizeof(NetworkInfo)) {
459 LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
460 IPC::ResponseBuilder rb{ctx, 2};
461 rb.Push(ResultBadInput);
462 return;
463 }
464
465 std::memcpy(&network_info, read_buffer.data(), read_buffer.size());
466
467 IPC::ResponseBuilder rb{ctx, 2};
468 rb.Push(ResultSuccess);
469 }
470
471 void Disconnect(Kernel::HLERequestContext& ctx) {
472 LOG_WARNING(Service_LDN, "(STUBBED) called");
473
474 IPC::ResponseBuilder rb{ctx, 2};
475 rb.Push(ResultSuccess);
476 }
477 void Initialize(Kernel::HLERequestContext& ctx) {
478 LOG_WARNING(Service_LDN, "(STUBBED) called");
479
480 const auto rc = InitializeImpl(ctx);
481
482 IPC::ResponseBuilder rb{ctx, 2};
483 rb.Push(rc);
484 }
485
486 void Finalize(Kernel::HLERequestContext& ctx) {
487 LOG_WARNING(Service_LDN, "(STUBBED) called");
488
489 is_initialized = false;
490
491 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(ResultSuccess); 492 rb.Push(ResultSuccess);
150 } 493 }
151 494
152 void Initialize2(Kernel::HLERequestContext& ctx) { 495 void Initialize2(Kernel::HLERequestContext& ctx) {
153 LOG_DEBUG(Service_LDN, "called"); 496 LOG_WARNING(Service_LDN, "(STUBBED) called");
154 497
155 is_initialized = true; 498 const auto rc = InitializeImpl(ctx);
156 499
157 IPC::ResponseBuilder rb{ctx, 2}; 500 IPC::ResponseBuilder rb{ctx, 2};
158 rb.Push(ERROR_DISABLED); 501 rb.Push(rc);
502 }
503
504 Result InitializeImpl(Kernel::HLERequestContext& ctx) {
505 const auto network_interface = Network::GetSelectedNetworkInterface();
506 if (!network_interface) {
507 LOG_ERROR(Service_LDN, "No network interface is set");
508 return ResultAirplaneModeEnabled;
509 }
510
511 is_initialized = true;
512 // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented
513 return ResultAirplaneModeEnabled;
159 } 514 }
160 515
161private: 516 KernelHelpers::ServiceContext service_context;
162 enum class State { 517 Kernel::KEvent* state_change_event;
163 None, 518 Network::RoomNetwork& room_network;
164 Initialized,
165 AccessPointOpened,
166 AccessPointCreated,
167 StationOpened,
168 StationConnected,
169 Error,
170 };
171 519
172 bool is_initialized{}; 520 bool is_initialized{};
173}; 521};
@@ -273,7 +621,7 @@ public:
273 LOG_WARNING(Service_LDN, "(STUBBED) called"); 621 LOG_WARNING(Service_LDN, "(STUBBED) called");
274 622
275 IPC::ResponseBuilder rb{ctx, 2}; 623 IPC::ResponseBuilder rb{ctx, 2};
276 rb.Push(ERROR_DISABLED); 624 rb.Push(ResultDisabled);
277 } 625 }
278}; 626};
279 627
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
index a0031ac71..6afe2ea6f 100644
--- a/src/core/hle/service/ldn/ldn.h
+++ b/src/core/hle/service/ldn/ldn.h
@@ -3,6 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/result.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/sm/sm.h"
11
6namespace Core { 12namespace Core {
7class System; 13class System;
8} 14}
diff --git a/src/core/hle/service/ldn/ldn_results.h b/src/core/hle/service/ldn/ldn_results.h
new file mode 100644
index 000000000..f340bda42
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn_results.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::LDN {
9
10constexpr Result ResultAdvertiseDataTooLarge{ErrorModule::LDN, 10};
11constexpr Result ResultAuthenticationFailed{ErrorModule::LDN, 20};
12constexpr Result ResultDisabled{ErrorModule::LDN, 22};
13constexpr Result ResultAirplaneModeEnabled{ErrorModule::LDN, 23};
14constexpr Result ResultInvalidNodeCount{ErrorModule::LDN, 30};
15constexpr Result ResultConnectionFailed{ErrorModule::LDN, 31};
16constexpr Result ResultBadState{ErrorModule::LDN, 32};
17constexpr Result ResultNoIpAddress{ErrorModule::LDN, 33};
18constexpr Result ResultInvalidBufferCount{ErrorModule::LDN, 50};
19constexpr Result ResultAccessPointConnectionFailed{ErrorModule::LDN, 65};
20constexpr Result ResultAuthenticationTimeout{ErrorModule::LDN, 66};
21constexpr Result ResultMaximumNodeCount{ErrorModule::LDN, 67};
22constexpr Result ResultBadInput{ErrorModule::LDN, 96};
23constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97};
24constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113};
25constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114};
26
27} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h
new file mode 100644
index 000000000..0c07a7397
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn_types.h
@@ -0,0 +1,284 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <fmt/format.h>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "network/network.h"
11
12namespace Service::LDN {
13
14constexpr size_t SsidLengthMax = 32;
15constexpr size_t AdvertiseDataSizeMax = 384;
16constexpr size_t UserNameBytesMax = 32;
17constexpr int NodeCountMax = 8;
18constexpr int StationCountMax = NodeCountMax - 1;
19constexpr size_t PassphraseLengthMax = 64;
20
21enum class SecurityMode : u16 {
22 All,
23 Retail,
24 Debug,
25};
26
27enum class NodeStateChange : u8 {
28 None,
29 Connect,
30 Disconnect,
31 DisconnectAndConnect,
32};
33
34enum class ScanFilterFlag : u32 {
35 None = 0,
36 LocalCommunicationId = 1 << 0,
37 SessionId = 1 << 1,
38 NetworkType = 1 << 2,
39 Ssid = 1 << 4,
40 SceneId = 1 << 5,
41 IntentId = LocalCommunicationId | SceneId,
42 NetworkId = IntentId | SessionId,
43};
44
45enum class NetworkType : u32 {
46 None,
47 General,
48 Ldn,
49 All,
50};
51
52enum class PackedNetworkType : u8 {
53 None,
54 General,
55 Ldn,
56 All,
57};
58
59enum class State : u32 {
60 None,
61 Initialized,
62 AccessPointOpened,
63 AccessPointCreated,
64 StationOpened,
65 StationConnected,
66 Error,
67};
68
69enum class DisconnectReason : s16 {
70 Unknown = -1,
71 None,
72 DisconnectedByUser,
73 DisconnectedBySystem,
74 DestroyedByUser,
75 DestroyedBySystem,
76 Rejected,
77 SignalLost,
78};
79
80enum class NetworkError {
81 Unknown = -1,
82 None = 0,
83 PortUnreachable,
84 TooManyPlayers,
85 VersionTooLow,
86 VersionTooHigh,
87 ConnectFailure,
88 ConnectNotFound,
89 ConnectTimeout,
90 ConnectRejected,
91 RejectFailed,
92};
93
94enum class AcceptPolicy : u8 {
95 AcceptAll,
96 RejectAll,
97 BlackList,
98 WhiteList,
99};
100
101enum class WifiChannel : s16 {
102 Default = 0,
103 wifi24_1 = 1,
104 wifi24_6 = 6,
105 wifi24_11 = 11,
106 wifi50_36 = 36,
107 wifi50_40 = 40,
108 wifi50_44 = 44,
109 wifi50_48 = 48,
110};
111
112enum class LinkLevel : s8 {
113 Bad,
114 Low,
115 Good,
116 Excelent,
117};
118
119struct NodeLatestUpdate {
120 NodeStateChange state_change;
121 INSERT_PADDING_BYTES(0x7); // Unknown
122};
123static_assert(sizeof(NodeLatestUpdate) == 0x8, "NodeLatestUpdate is an invalid size");
124
125struct SessionId {
126 u64 high;
127 u64 low;
128
129 bool operator==(const SessionId&) const = default;
130};
131static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
132
133struct IntentId {
134 u64 local_communication_id;
135 INSERT_PADDING_BYTES(0x2); // Reserved
136 u16 scene_id;
137 INSERT_PADDING_BYTES(0x4); // Reserved
138};
139static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
140
141struct NetworkId {
142 IntentId intent_id;
143 SessionId session_id;
144};
145static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
146
147struct Ssid {
148 u8 length;
149 std::array<char, SsidLengthMax + 1> raw;
150
151 std::string GetStringValue() const {
152 return std::string(raw.data(), length);
153 }
154};
155static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size");
156
157struct Ipv4Address {
158 union {
159 u32 raw{};
160 std::array<u8, 4> bytes;
161 };
162
163 std::string GetStringValue() const {
164 return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]);
165 }
166};
167static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
168
169struct MacAddress {
170 std::array<u8, 6> raw{};
171
172 friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
173};
174static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size");
175
176struct ScanFilter {
177 NetworkId network_id;
178 NetworkType network_type;
179 MacAddress mac_address;
180 Ssid ssid;
181 INSERT_PADDING_BYTES(0x10);
182 ScanFilterFlag flag;
183};
184static_assert(sizeof(ScanFilter) == 0x60, "ScanFilter is an invalid size");
185
186struct CommonNetworkInfo {
187 MacAddress bssid;
188 Ssid ssid;
189 WifiChannel channel;
190 LinkLevel link_level;
191 PackedNetworkType network_type;
192 INSERT_PADDING_BYTES(0x4);
193};
194static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
195
196struct NodeInfo {
197 Ipv4Address ipv4_address;
198 MacAddress mac_address;
199 s8 node_id;
200 u8 is_connected;
201 std::array<u8, UserNameBytesMax + 1> user_name;
202 INSERT_PADDING_BYTES(0x1); // Reserved
203 s16 local_communication_version;
204 INSERT_PADDING_BYTES(0x10); // Reserved
205};
206static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
207
208struct LdnNetworkInfo {
209 std::array<u8, 0x10> security_parameter;
210 SecurityMode security_mode;
211 AcceptPolicy station_accept_policy;
212 u8 has_action_frame;
213 INSERT_PADDING_BYTES(0x2); // Padding
214 u8 node_count_max;
215 u8 node_count;
216 std::array<NodeInfo, NodeCountMax> nodes;
217 INSERT_PADDING_BYTES(0x2); // Reserved
218 u16 advertise_data_size;
219 std::array<u8, AdvertiseDataSizeMax> advertise_data;
220 INSERT_PADDING_BYTES(0x8C); // Reserved
221 u64 random_authentication_id;
222};
223static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
224
225struct NetworkInfo {
226 NetworkId network_id;
227 CommonNetworkInfo common;
228 LdnNetworkInfo ldn;
229};
230static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
231
232struct SecurityConfig {
233 SecurityMode security_mode;
234 u16 passphrase_size;
235 std::array<u8, PassphraseLengthMax> passphrase;
236};
237static_assert(sizeof(SecurityConfig) == 0x44, "SecurityConfig is an invalid size");
238
239struct UserConfig {
240 std::array<u8, UserNameBytesMax + 1> user_name;
241 INSERT_PADDING_BYTES(0xF); // Reserved
242};
243static_assert(sizeof(UserConfig) == 0x30, "UserConfig is an invalid size");
244
245#pragma pack(push, 4)
246struct ConnectRequest {
247 SecurityConfig security_config;
248 UserConfig user_config;
249 u32 local_communication_version;
250 u32 option_unknown;
251 NetworkInfo network_info;
252};
253static_assert(sizeof(ConnectRequest) == 0x4FC, "ConnectRequest is an invalid size");
254#pragma pack(pop)
255
256struct SecurityParameter {
257 std::array<u8, 0x10> data; // Data, used with the same key derivation as SecurityConfig
258 SessionId session_id;
259};
260static_assert(sizeof(SecurityParameter) == 0x20, "SecurityParameter is an invalid size");
261
262struct NetworkConfig {
263 IntentId intent_id;
264 WifiChannel channel;
265 u8 node_count_max;
266 INSERT_PADDING_BYTES(0x1); // Reserved
267 u16 local_communication_version;
268 INSERT_PADDING_BYTES(0xA); // Reserved
269};
270static_assert(sizeof(NetworkConfig) == 0x20, "NetworkConfig is an invalid size");
271
272struct AddressEntry {
273 Ipv4Address ipv4_address;
274 MacAddress mac_address;
275 INSERT_PADDING_BYTES(0x2); // Reserved
276};
277static_assert(sizeof(AddressEntry) == 0xC, "AddressEntry is an invalid size");
278
279struct AddressList {
280 std::array<AddressEntry, 0x8> addresses;
281};
282static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
283
284} // namespace Service::LDN
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index fa8efd22e..a69ae7725 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -33,9 +33,10 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
33} 33}
34 34
35VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { 35VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) {
36 // Mailbox doesn't lock the application like fifo (vsync), prefer it 36 // Mailbox (triple buffering) doesn't lock the application like fifo (vsync),
37 // prefer it if vsync option is not selected
37 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); 38 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR);
38 if (found_mailbox != modes.end()) { 39 if (found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) {
39 return VK_PRESENT_MODE_MAILBOX_KHR; 40 return VK_PRESENT_MODE_MAILBOX_KHR;
40 } 41 }
41 if (!Settings::values.use_speed_limit.GetValue()) { 42 if (!Settings::values.use_speed_limit.GetValue()) {
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index f6b389ede..50007338f 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -221,6 +221,9 @@ if (ENABLE_QT_TRANSLATION)
221 # Update source TS file if enabled 221 # Update source TS file if enabled
222 if (GENERATE_QT_TRANSLATION) 222 if (GENERATE_QT_TRANSLATION)
223 get_target_property(SRCS yuzu SOURCES) 223 get_target_property(SRCS yuzu SOURCES)
224 # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
225 # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
226 set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
224 qt_create_translation(QM_FILES 227 qt_create_translation(QM_FILES
225 ${SRCS} 228 ${SRCS}
226 ${UIS} 229 ${UIS}
@@ -229,7 +232,13 @@ if (ENABLE_QT_TRANSLATION)
229 -source-language en_US 232 -source-language en_US
230 -target-language en_US 233 -target-language en_US
231 ) 234 )
232 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts) 235
236 # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
237 set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
238 set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
239 qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
240
241 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
233 endif() 242 endif()
234 243
235 # Find all TS files except en.ts 244 # Find all TS files except en.ts
@@ -239,6 +248,9 @@ if (ENABLE_QT_TRANSLATION)
239 # Compile TS files to QM files 248 # Compile TS files to QM files
240 qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) 249 qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS})
241 250
251 # Compile english plurals TS file to en.qm
252 qt_add_translation(LANGUAGES_QM ${PROJECT_SOURCE_DIR}/dist/english_plurals/en.ts)
253
242 # Build a QRC file from the QM file list 254 # Build a QRC file from the QM file list
243 set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) 255 set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc)
244 file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n") 256 file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n")
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui
index c4ffb293e..aea82809d 100644
--- a/src/yuzu/aboutdialog.ui
+++ b/src/yuzu/aboutdialog.ui
@@ -7,7 +7,7 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>616</width> 9 <width>616</width>
10 <height>261</height> 10 <height>294</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -165,6 +165,7 @@ p, li { white-space: pre-wrap; }
165 </widget> 165 </widget>
166 <resources> 166 <resources>
167 <include location="../../dist/qt_themes_default/default/default.qrc"/> 167 <include location="../../dist/qt_themes_default/default/default.qrc"/>
168 <include location="../../dist/qt_themes/default/default.qrc"/>
168 </resources> 169 </resources>
169 <connections> 170 <connections>
170 <connection> 171 <connection>
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 58f1239bf..da6e5aa88 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -73,7 +73,7 @@ const std::array<int, 2> Config::default_ringcon_analogs{{
73const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ 73const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
74 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, 74 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}},
75 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, 75 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}},
76 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, 76 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}},
77 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, 77 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}},
78 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, 78 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}},
79 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, 79 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}},
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index a5bcee415..6034d8581 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -120,10 +120,10 @@
120 </sizepolicy> 120 </sizepolicy>
121 </property> 121 </property>
122 <property name="maximum"> 122 <property name="maximum">
123 <number>100</number> 123 <number>200</number>
124 </property> 124 </property>
125 <property name="pageStep"> 125 <property name="pageStep">
126 <number>10</number> 126 <number>5</number>
127 </property> 127 </property>
128 <property name="orientation"> 128 <property name="orientation">
129 <enum>Qt::Horizontal</enum> 129 <enum>Qt::Horizontal</enum>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 96de0b3d1..d6d819364 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -75,7 +75,7 @@
75 <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> 75 <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string>
76 </property> 76 </property>
77 <property name="text"> 77 <property name="text">
78 <string>Use VSync (OpenGL only)</string> 78 <string>Use VSync</string>
79 </property> 79 </property>
80 </widget> 80 </widget>
81 </item> 81 </item>
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 2e98ede8e..48f71b53c 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -219,6 +219,7 @@ void ConfigureUi::InitializeLanguageComboBox() {
219 for (const auto& lang : languages) { 219 for (const auto& lang : languages) {
220 if (QString::fromLatin1(lang.id) == QStringLiteral("en")) { 220 if (QString::fromLatin1(lang.id) == QStringLiteral("en")) {
221 ui->language_combobox->addItem(lang.name, QStringLiteral("en")); 221 ui->language_combobox->addItem(lang.name, QStringLiteral("en"));
222 language_files.removeOne(QStringLiteral("en.qm"));
222 continue; 223 continue;
223 } 224 }
224 for (int i = 0; i < language_files.size(); ++i) { 225 for (int i = 0; i < language_files.size(); ++i) {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 041e6ac11..c4b1f65bd 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -286,7 +286,7 @@ void GameList::OnUpdateThemedIcons() {
286 } 286 }
287 case GameListItemType::AddDir: 287 case GameListItemType::AddDir:
288 child->setData( 288 child->setData(
289 QIcon::fromTheme(QStringLiteral("plus")) 289 QIcon::fromTheme(QStringLiteral("list-add"))
290 .pixmap(icon_size) 290 .pixmap(icon_size)
291 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), 291 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
292 Qt::DecorationRole); 292 Qt::DecorationRole);
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index e7667cf60..0e19be22d 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -294,7 +294,7 @@ public:
294 294
295 const int icon_size = UISettings::values.folder_icon_size.GetValue(); 295 const int icon_size = UISettings::values.folder_icon_size.GetValue();
296 296
297 setData(QIcon::fromTheme(QStringLiteral("plus")) 297 setData(QIcon::fromTheme(QStringLiteral("list-add"))
298 .pixmap(icon_size) 298 .pixmap(icon_size)
299 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), 299 .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
300 Qt::DecorationRole); 300 Qt::DecorationRole);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 653280642..8bd1f92f7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -257,6 +257,18 @@ static QString PrettyProductName() {
257 return QSysInfo::prettyProductName(); 257 return QSysInfo::prettyProductName();
258} 258}
259 259
260bool GMainWindow::CheckDarkMode() {
261#ifdef __linux__
262 const QPalette test_palette(qApp->palette());
263 const QColor text_color = test_palette.color(QPalette::Active, QPalette::Text);
264 const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
265 return (text_color.value() > window_color.value());
266#else
267 // TODO: Windows
268 return false;
269#endif // __linux__
270}
271
260GMainWindow::GMainWindow(bool has_broken_vulkan) 272GMainWindow::GMainWindow(bool has_broken_vulkan)
261 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, 273 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
262 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, 274 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
@@ -274,6 +286,13 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
274 ui->setupUi(this); 286 ui->setupUi(this);
275 statusBar()->hide(); 287 statusBar()->hide();
276 288
289 // Check dark mode before a theme is loaded
290 os_dark_mode = CheckDarkMode();
291 startup_icon_theme = QIcon::themeName();
292 // fallback can only be set once, colorful theme icons are okay on both light/dark
293 QIcon::setFallbackThemeName(QStringLiteral("colorful"));
294 QIcon::setFallbackSearchPaths(QStringList(QStringLiteral(":/icons")));
295
277 default_theme_paths = QIcon::themeSearchPaths(); 296 default_theme_paths = QIcon::themeSearchPaths();
278 UpdateUITheme(); 297 UpdateUITheme();
279 298
@@ -1075,7 +1094,7 @@ void GMainWindow::InitializeHotkeys() {
1075 connect_shortcut(QStringLiteral("Audio Mute/Unmute"), 1094 connect_shortcut(QStringLiteral("Audio Mute/Unmute"),
1076 [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); 1095 [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
1077 connect_shortcut(QStringLiteral("Audio Volume Down"), [] { 1096 connect_shortcut(QStringLiteral("Audio Volume Down"), [] {
1078 const auto current_volume = static_cast<int>(Settings::values.volume.GetValue()); 1097 const auto current_volume = static_cast<s32>(Settings::values.volume.GetValue());
1079 int step = 5; 1098 int step = 5;
1080 if (current_volume <= 30) { 1099 if (current_volume <= 30) {
1081 step = 2; 1100 step = 2;
@@ -1083,11 +1102,10 @@ void GMainWindow::InitializeHotkeys() {
1083 if (current_volume <= 6) { 1102 if (current_volume <= 6) {
1084 step = 1; 1103 step = 1;
1085 } 1104 }
1086 const auto new_volume = std::max(current_volume - step, 0); 1105 Settings::values.volume.SetValue(std::max(current_volume - step, 0));
1087 Settings::values.volume.SetValue(static_cast<u8>(new_volume));
1088 }); 1106 });
1089 connect_shortcut(QStringLiteral("Audio Volume Up"), [] { 1107 connect_shortcut(QStringLiteral("Audio Volume Up"), [] {
1090 const auto current_volume = static_cast<int>(Settings::values.volume.GetValue()); 1108 const auto current_volume = static_cast<s32>(Settings::values.volume.GetValue());
1091 int step = 5; 1109 int step = 5;
1092 if (current_volume < 30) { 1110 if (current_volume < 30) {
1093 step = 2; 1111 step = 2;
@@ -1095,8 +1113,7 @@ void GMainWindow::InitializeHotkeys() {
1095 if (current_volume < 6) { 1113 if (current_volume < 6) {
1096 step = 1; 1114 step = 1;
1097 } 1115 }
1098 const auto new_volume = std::min(current_volume + step, 100); 1116 Settings::values.volume.SetValue(current_volume + step);
1099 Settings::values.volume.SetValue(static_cast<u8>(new_volume));
1100 }); 1117 });
1101 connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { 1118 connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] {
1102 Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); 1119 Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue());
@@ -3935,8 +3952,21 @@ void GMainWindow::filterBarSetChecked(bool state) {
3935 emit(OnToggleFilterBar()); 3952 emit(OnToggleFilterBar());
3936} 3953}
3937 3954
3955static void AdjustLinkColor() {
3956 QPalette new_pal(qApp->palette());
3957 if (UISettings::IsDarkTheme()) {
3958 new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255));
3959 } else {
3960 new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255));
3961 }
3962 if (qApp->palette().color(QPalette::Link) != new_pal.color(QPalette::Link)) {
3963 qApp->setPalette(new_pal);
3964 }
3965}
3966
3938void GMainWindow::UpdateUITheme() { 3967void GMainWindow::UpdateUITheme() {
3939 const QString default_theme = QStringLiteral("default"); 3968 const QString default_theme =
3969 QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second);
3940 QString current_theme = UISettings::values.theme; 3970 QString current_theme = UISettings::values.theme;
3941 QStringList theme_paths(default_theme_paths); 3971 QStringList theme_paths(default_theme_paths);
3942 3972
@@ -3944,6 +3974,23 @@ void GMainWindow::UpdateUITheme() {
3944 current_theme = default_theme; 3974 current_theme = default_theme;
3945 } 3975 }
3946 3976
3977#ifdef _WIN32
3978 QIcon::setThemeName(current_theme);
3979 AdjustLinkColor();
3980#else
3981 if (current_theme == QStringLiteral("default") || current_theme == QStringLiteral("colorful")) {
3982 QIcon::setThemeName(current_theme == QStringLiteral("colorful") ? current_theme
3983 : startup_icon_theme);
3984 QIcon::setThemeSearchPaths(theme_paths);
3985 if (CheckDarkMode()) {
3986 current_theme = QStringLiteral("default_dark");
3987 }
3988 } else {
3989 QIcon::setThemeName(current_theme);
3990 QIcon::setThemeSearchPaths(QStringList(QStringLiteral(":/icons")));
3991 AdjustLinkColor();
3992 }
3993#endif
3947 if (current_theme != default_theme) { 3994 if (current_theme != default_theme) {
3948 QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)}; 3995 QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)};
3949 QFile f(theme_uri); 3996 QFile f(theme_uri);
@@ -3966,25 +4013,9 @@ void GMainWindow::UpdateUITheme() {
3966 qApp->setStyleSheet({}); 4013 qApp->setStyleSheet({});
3967 setStyleSheet({}); 4014 setStyleSheet({});
3968 } 4015 }
3969
3970 QPalette new_pal(qApp->palette());
3971 if (UISettings::IsDarkTheme()) {
3972 new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255));
3973 } else {
3974 new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255));
3975 }
3976 qApp->setPalette(new_pal);
3977
3978 QIcon::setThemeName(current_theme);
3979 QIcon::setThemeSearchPaths(theme_paths);
3980} 4016}
3981 4017
3982void GMainWindow::LoadTranslation() { 4018void GMainWindow::LoadTranslation() {
3983 // If the selected language is English, no need to install any translation
3984 if (UISettings::values.language == QStringLiteral("en")) {
3985 return;
3986 }
3987
3988 bool loaded; 4019 bool loaded;
3989 4020
3990 if (UISettings::values.language.isEmpty()) { 4021 if (UISettings::values.language.isEmpty()) {
@@ -4027,6 +4058,26 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
4027 discord_rpc->Update(); 4058 discord_rpc->Update();
4028} 4059}
4029 4060
4061void GMainWindow::changeEvent(QEvent* event) {
4062#ifdef __linux__
4063 // PaletteChange event appears to only reach so far into the GUI, explicitly asking to
4064 // UpdateUITheme is a decent work around
4065 if (event->type() == QEvent::PaletteChange) {
4066 const QPalette test_palette(qApp->palette());
4067 const QString current_theme = UISettings::values.theme;
4068 // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too
4069 static QColor last_window_color;
4070 const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
4071 if (last_window_color != window_color && (current_theme == QStringLiteral("default") ||
4072 current_theme == QStringLiteral("colorful"))) {
4073 UpdateUITheme();
4074 }
4075 last_window_color = window_color;
4076 }
4077#endif // __linux__
4078 QWidget::changeEvent(event);
4079}
4080
4030#ifdef main 4081#ifdef main
4031#undef main 4082#undef main
4032#endif 4083#endif
@@ -4072,6 +4123,15 @@ int main(int argc, char* argv[]) {
4072 QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); 4123 QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
4073 QApplication app(argc, argv); 4124 QApplication app(argc, argv);
4074 4125
4126 // Workaround for QTBUG-85409, for Suzhou numerals the number 1 is actually \u3021
4127 // so we can see if we get \u3008 instead
4128 // TL;DR all other number formats are consecutive in unicode code points
4129 // This bug is fixed in Qt6, specifically 6.0.0-alpha1
4130 const QLocale locale = QLocale::system();
4131 if (QStringLiteral("\u3008") == locale.toString(1)) {
4132 QLocale::setDefault(QLocale::system().name());
4133 }
4134
4075 // Qt changes the locale and causes issues in float conversion using std::to_string() when 4135 // Qt changes the locale and causes issues in float conversion using std::to_string() when
4076 // generating shaders 4136 // generating shaders
4077 setlocale(LC_ALL, "C"); 4137 setlocale(LC_ALL, "C");
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index e13b38b24..1ae2b93d9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -251,6 +251,7 @@ private:
251 bool ConfirmForceLockedExit(); 251 bool ConfirmForceLockedExit();
252 void RequestGameExit(); 252 void RequestGameExit();
253 void RequestGameResume(); 253 void RequestGameResume();
254 void changeEvent(QEvent* event) override;
254 void closeEvent(QCloseEvent* event) override; 255 void closeEvent(QCloseEvent* event) override;
255 256
256#ifdef __linux__ 257#ifdef __linux__
@@ -347,6 +348,7 @@ private:
347 void OpenURL(const QUrl& url); 348 void OpenURL(const QUrl& url);
348 void LoadTranslation(); 349 void LoadTranslation();
349 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); 350 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
351 bool CheckDarkMode();
350 352
351 QString GetTasStateDescription() const; 353 QString GetTasStateDescription() const;
352 354
@@ -392,6 +394,9 @@ private:
392 QTimer mouse_hide_timer; 394 QTimer mouse_hide_timer;
393 QTimer mouse_center_timer; 395 QTimer mouse_center_timer;
394 396
397 QString startup_icon_theme;
398 bool os_dark_mode = false;
399
395 // FS 400 // FS
396 std::shared_ptr<FileSys::VfsFilesystem> vfs; 401 std::shared_ptr<FileSys::VfsFilesystem> vfs;
397 std::unique_ptr<FileSys::ManualContentProvider> provider; 402 std::unique_ptr<FileSys::ManualContentProvider> provider;
diff --git a/src/yuzu/multiplayer/direct_connect.ui b/src/yuzu/multiplayer/direct_connect.ui
index 681b6bf69..57d6ec25a 100644
--- a/src/yuzu/multiplayer/direct_connect.ui
+++ b/src/yuzu/multiplayer/direct_connect.ui
@@ -83,7 +83,7 @@
83 <number>5</number> 83 <number>5</number>
84 </property> 84 </property>
85 <property name="placeholderText"> 85 <property name="placeholderText">
86 <string>24872</string> 86 <string notr="true" extracomment="placeholder string that tells user default port">24872</string>
87 </property> 87 </property>
88 </widget> 88 </widget>
89 </item> 89 </item>