Compare commits

...

17 Commits

Author SHA1 Message Date
greem
bf083a716c use new workflow type in conditions 2026-05-05 10:12:06 +00:00
greem
2d2661298c Update .forgejo/workflows/build.yml 2026-05-05 09:29:41 +00:00
greem
c4788154fd even more annoying skill issue! 2026-05-05 09:15:54 +00:00
greem
49dd56953c annoying error 2026-05-05 08:52:08 +00:00
greem
722eb93554 Use a dedicated access token instead of the runner-generated one. 2026-05-05 08:07:38 +00:00
ryuadmin
b0179e6433 [ci skip] Improve logging for PR build comment step. 2026-05-05 07:50:58 +00:00
ryuadmin
1d3d4197b7 fix: *hopefully* fix build comments 2026-05-05 06:22:51 +00:00
GreemDev
d2b2d65061 chore: Remove unused variable. 2026-05-04 23:33:28 -05:00
GreemDev
e1dcaef709 fix: don't try to access .length if artifacts is undefined 2026-05-04 23:32:53 -05:00
GreemDev
b222f671f3 fix: use run_number instead of run_id 2026-05-04 23:32:35 -05:00
Babib3l
4d0cd61b6a Fix Windows console hide path targeting the foreground window (#32)
This PR addresses [Ryubing/Issues#345](https://github.com/Ryubing/Issues/issues/345) by fixing the Windows console hide/show path so it only acts on Ryujinx’s own console window instead of whatever window happens to be focused during startup. Previously, when Show Console was disabled, the helper could race with focus changes and end up affecting another app or shell window while leaving the console visible; this change removes that foreground-window dependency and keeps the startup behavior scoped to the Ryujinx console.

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/32
2026-05-05 03:48:23 +00:00
greem
4e86159bce [ci skip] fix: Invalid workflow templates in github-script source 2026-05-05 03:15:33 +00:00
GreemDev
0d66cfa281 chore: Update actions/github-script to v9 (not sure how this got lost)
also add explicit semicolon for getOctokit
2026-05-04 21:18:33 -05:00
GreemDev
e656de5fff fix: use ubuntu-latest in release.yml post-ci steps. 2026-05-04 20:46:40 -05:00
GreemDev
518dd65484 fix: Collapse PR comment into PR build workflow
Not sure why this was ever separate, and Forgejo doesn't seem to run 'workflow_run` post-execution workflows.
2026-05-04 20:45:45 -05:00
GreemDev
88421959a6 Rework nightly_pr_comment for Forgejo Actions 2026-05-04 20:12:38 -05:00
Max
87ce5162be skia-natives (again) (#78)
Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/78
2026-05-04 12:42:52 +00:00
10 changed files with 134 additions and 101 deletions

View File

@@ -1,7 +1,7 @@
name: Build PR name: Build PR
on: on:
pull_request: pull_request_target:
branches: [ master ] branches: [ master ]
paths: paths:
- '**' - '**'
@@ -63,7 +63,7 @@ jobs:
- name: Change config filename - name: Change config filename
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash shell: bash
if: forgejo.event_name == 'pull_request' if: forgejo.event_name == 'pull_request_target'
- name: 'Cache: ~/.nuget/packages' - name: 'Cache: ~/.nuget/packages'
uses: actions/cache@v5 uses: actions/cache@v5
@@ -85,7 +85,7 @@ jobs:
- name: Publish Ryujinx - name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.result }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.result }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained
if: forgejo.event_name == 'pull_request' if: forgejo.event_name == 'pull_request_target'
- name: Packing Windows builds - name: Packing Windows builds
if: contains(matrix.platform.name, 'win') if: contains(matrix.platform.name, 'win')
@@ -98,10 +98,10 @@ jobs:
with: with:
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }} name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}
path: artifact path: artifact
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'win') if: forgejo.event_name == 'pull_request_target' && contains(matrix.platform.name, 'win')
- name: Build AppImage - name: Build AppImage
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'linux') if: forgejo.event_name == 'pull_request_target' && contains(matrix.platform.name, 'linux')
run: | run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
@@ -134,7 +134,7 @@ jobs:
- name: Upload Ryujinx AppImage artifact - name: Upload Ryujinx AppImage artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v5
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'linux') if: forgejo.event_name == 'pull_request_target' && contains(matrix.platform.name, 'linux')
with: with:
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}-AppImage name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}-AppImage
path: publish_appimage path: publish_appimage
@@ -182,7 +182,7 @@ jobs:
- name: Change config filename - name: Change config filename
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash shell: bash
if: forgejo.event_name == 'pull_request' if: forgejo.event_name == 'pull_request_target'
- name: 'Cache: ~/.nuget/packages' - name: 'Cache: ~/.nuget/packages'
uses: actions/cache@v5 uses: actions/cache@v5
@@ -201,4 +201,47 @@ jobs:
with: with:
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-macos_universal name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-macos_universal
path: "publish/*.tar.gz" path: "publish/*.tar.gz"
if: forgejo.event_name == 'pull_request' if: forgejo.event_name == 'pull_request_target'
post_comment:
name: Post comment linking uploaded artifacts
runs-on: ubuntu-latest
needs:
- build
- build_macos
steps:
- uses: actions/github-script@v9
env:
COMMENTER_TOKEN: ${{ secrets.COMMENTER_TOKEN }}
with:
github-token: 'n/a'
script: |
const forgejo = getOctokit(process.env.COMMENTER_TOKEN, {
baseUrl: 'https://git.ryujinx.app/api/v1'
});
const {owner, repo} = context.repo;
const run_id = ${{ env.FORGEJO_RUN_ID }};
const issue_number = ${{ forgejo.event.pull_request.number }};
core.info(`Using run ID ${run_id} from pull request ${issue_number}`);
const {data: {artifacts}} = await forgejo.rest.actions.listWorkflowRunArtifacts({owner, repo, run_id});
if (artifacts == undefined || !artifacts.length) {
return core.error(`No artifacts found for run ID`);
}
let body = `Download the artifacts for this pull request:\n`;
for (const art of artifacts) {
const url = `https://git.ryujinx.app/api/v1/repos/${owner}/${repo}/actions/artifacts/${art.id}/zip`;
body += `\n* [${art.name}](${url})`;
}
const {data: comments} = await forgejo.rest.issues.listComments({repo, owner, issue_number});
const existing_comment = comments.find((c) => c.user.login === 'forgejo-actions');
if (existing_comment) {
core.info(`Updating comment ${existing_comment.id}`);
await forgejo.rest.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
} else {
core.info(`Creating a comment`);
await forgejo.rest.issues.createComment({repo, owner, issue_number, body});
}

View File

@@ -143,9 +143,7 @@ jobs:
macos_release: macos_release:
name: Release MacOS universal name: Release MacOS universal
runs-on: docker runs-on: ubuntu-latest
container:
image: ghcr.io/catthehacker/ubuntu:act-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
@@ -207,7 +205,7 @@ jobs:
post_ci: post_ci:
name: Post-CI Steps name: Post-CI Steps
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
needs: needs:
- macos_release - macos_release
- release - release

View File

@@ -1,61 +0,0 @@
name: Comment PR artifacts links
on:
workflow_run:
workflows: ['Build PR']
types: [completed]
jobs:
pr_comment:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
with:
script: |
const {owner, repo} = context.repo;
const run_id = ${{github.event.workflow_run.id}};
const pull_head_sha = '${{github.event.workflow_run.head_sha}}';
const issue_number = await (async () => {
const pulls = await github.rest.pulls.list({owner, repo});
for await (const {data} of github.paginate.iterator(pulls)) {
for (const pull of data) {
if (pull.head.sha === pull_head_sha) {
return pull.number;
}
}
}
})();
if (issue_number) {
core.info(`Using pull request ${issue_number}`);
} else {
return core.error(`No matching pull request found`);
}
const {data: {artifacts}} = await github.rest.actions.listWorkflowRunArtifacts({owner, repo, run_id});
if (!artifacts.length) {
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request:\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) {
const url = `https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip`;
if (art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
} else {
body += `\n* [${art.name}](${url})`;
}
}
hidden_debug_artifacts += `\n</details>`;
body += hidden_debug_artifacts;
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]');
if (existing_comment) {
core.info(`Updating comment ${existing_comment.id}`);
await github.rest.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
} else {
core.info(`Creating a comment`);
await github.rest.issues.createComment({repo, owner, issue_number, body});
}

View File

@@ -57,7 +57,9 @@
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
<PackageVersion Include="SkiaSharp" Version="2.88.9" /> <PackageVersion Include="SkiaSharp" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" /> <PackageVersion Include="SkiaSharp.NativeAssets.Win32" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.macOS" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" />
<PackageVersion Include="SPB" Version="0.0.4-build32" /> <PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.15" /> <PackageVersion Include="System.IO.Hashing" Version="9.0.15" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.3" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.3" />

View File

@@ -21425,6 +21425,31 @@
"zh_TW": "需要重新啟動 Ryujinx" "zh_TW": "需要重新啟動 Ryujinx"
} }
}, },
{
"ID": "SettingsShowConsoleRestartMessage",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "The console will be available the next time Ryujinx starts.",
"es_ES": "La consola estará disponible la próxima vez que se inicie Ryujinx.",
"fr_FR": "La console sera disponible au prochain démarrage de Ryujinx.",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "SettingsGpuBackendRestartMessage", "ID": "SettingsGpuBackendRestartMessage",
"Translations": { "Translations": {

View File

@@ -12,20 +12,12 @@ namespace Ryujinx.Common.Helper
private static partial nint GetConsoleWindow(); private static partial nint GetConsoleWindow();
[SupportedOSPlatform("windows")] [SupportedOSPlatform("windows")]
[LibraryImport("user32")] [LibraryImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static partial bool ShowWindow(nint hWnd, int nCmdShow); private static partial bool FreeConsole();
[SupportedOSPlatform("windows")]
[LibraryImport("user32")]
private static partial nint GetForegroundWindow();
[SupportedOSPlatform("windows")]
[LibraryImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SetForegroundWindow(nint hWnd);
public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows(); public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows();
public static bool HasConsoleWindow => OperatingSystem.IsWindows() && GetConsoleWindow() != nint.Zero;
public static void SetConsoleWindowState(bool show) public static void SetConsoleWindowState(bool show)
{ {
@@ -42,22 +34,31 @@ namespace Ryujinx.Common.Helper
[SupportedOSPlatform("windows")] [SupportedOSPlatform("windows")]
private static void SetConsoleWindowStateWindows(bool show) private static void SetConsoleWindowStateWindows(bool show)
{ {
const int SW_HIDE = 0; if (show)
const int SW_SHOW = 5;
nint hWnd = GetConsoleWindow();
if (hWnd == nint.Zero)
{ {
Logger.Warning?.Print(LogClass.Application, "Attempted to show/hide console window but console window does not exist"); if (GetConsoleWindow() != nint.Zero)
{
Logger.SetConsoleTargetEnabled(true);
}
return; return;
} }
SetForegroundWindow(hWnd); Logger.SetConsoleTargetEnabled(false);
DetachConsole();
}
hWnd = GetForegroundWindow(); [SupportedOSPlatform("windows")]
private static void DetachConsole()
{
if (GetConsoleWindow() == nint.Zero)
{
return;
}
ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); if (!FreeConsole())
{
Logger.Warning?.Print(LogClass.Application, "Attempted to detach console window but the operation failed");
}
} }
} }
} }

View File

@@ -136,11 +136,7 @@ namespace Ryujinx.Common.Logging
_time = Stopwatch.StartNew(); _time = Stopwatch.StartNew();
// Logger should log to console by default SetConsoleTargetEnabled(true);
AddTarget(new AsyncLogTargetWrapper(
new ConsoleLogTarget("console"),
1000,
AsyncLogTargetOverflowAction.Discard));
Notice = new Log(LogLevel.Notice); Notice = new Log(LogLevel.Notice);
@@ -173,6 +169,21 @@ namespace Ryujinx.Common.Logging
Updated += target.Log; Updated += target.Log;
} }
public static void SetConsoleTargetEnabled(bool enabled)
{
if (enabled)
{
AddTarget(new AsyncLogTargetWrapper(
new ConsoleLogTarget("console"),
1000,
AsyncLogTargetOverflowAction.Discard));
}
else
{
RemoveTarget("console");
}
}
public static void RemoveTarget(string target) public static void RemoveTarget(string target)
{ {
ILogTarget logTarget = GetTarget(target); ILogTarget logTarget = GetTarget(target);

View File

@@ -27,7 +27,9 @@
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" /> <PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
<PackageReference Include="MsgPack.Cli" /> <PackageReference Include="MsgPack.Cli" />
<PackageReference Include="SkiaSharp" /> <PackageReference Include="SkiaSharp" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" /> <PackageReference Include="SkiaSharp.NativeAssets.Win32" />
<PackageReference Include="SkiaSharp.NativeAssets.macOS" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" />
<PackageReference Include="NetCoreServer" /> <PackageReference Include="NetCoreServer" />
<PackageReference Include="Open.NAT.Core" /> <PackageReference Include="Open.NAT.Core" />
</ItemGroup> </ItemGroup>

View File

@@ -49,6 +49,9 @@
<PackageReference Include="SharpCompress" /> <PackageReference Include="SharpCompress" />
<PackageReference Include="Svg.Controls.Avalonia" /> <PackageReference Include="Svg.Controls.Avalonia" />
<PackageReference Include="Svg.Controls.Skia.Avalonia" /> <PackageReference Include="Svg.Controls.Skia.Avalonia" />
<PackageReference Include="SkiaSharp.NativeAssets.Win32" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'win-arm64'" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Condition="'$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'win-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
<PackageReference Include="DynamicData" /> <PackageReference Include="DynamicData" />
<PackageReference Include="FluentAvaloniaUI" /> <PackageReference Include="FluentAvaloniaUI" />
<PackageReference Include="CommandLineParser" /> <PackageReference Include="CommandLineParser" />

View File

@@ -656,10 +656,19 @@ namespace Ryujinx.Ava.UI.ViewModels
get => ConfigurationState.Instance.UI.ShowConsole; get => ConfigurationState.Instance.UI.ShowConsole;
set set
{ {
bool restartRequired = value && !ConsoleHelper.HasConsoleWindow;
ConfigurationState.Instance.UI.ShowConsole.Value = value; ConfigurationState.Instance.UI.ShowConsole.Value = value;
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
if (restartRequired)
{
NotificationHelper.ShowInformation(
LocaleManager.Instance[LocaleKeys.SettingsAppRequiredRestartMessage],
LocaleManager.Instance[LocaleKeys.SettingsShowConsoleRestartMessage]);
}
OnPropertyChanged(); OnPropertyChanged();
} }
} }