Skip to content

Commit 56fc96f

Browse files
committed
ui: Add menu item to report a GitHub title issue
Prepopulates some of the members in the title issue template. Fixes #473 Obviates #1942
1 parent 8c7de72 commit 56fc96f

File tree

6 files changed

+260
-1
lines changed

6 files changed

+260
-1
lines changed

include/qemu/http.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ typedef struct http_progress_cb_info {
3535
size_t ultotal;
3636
} http_progress_cb_info;
3737

38+
bool ensure_libcurl_initialized(Error **errp);
39+
3840
int http_get(const char *url, GByteArray *response_body,
3941
http_progress_cb_info *progress_info, Error **errp);
4042
int http_post_json(const char *url, const char *json_data, Error **errp);

ui/xui/github-issue.cc

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#include "github-issue.hh"
2+
3+
#include <string>
4+
5+
#include "common.hh"
6+
#include <curl/curl.h>
7+
#include <glib/gunicode.h>
8+
#include "hw/xbox/nv2a/nv2a.h"
9+
#include "qemu/http.h"
10+
#include "ui/xemu-os-utils.h"
11+
#include "ui/xemu-settings.h"
12+
#include "xemu-version.h"
13+
#include "xemu-xbe.h"
14+
15+
static constexpr char base_compatibility_url[] = "https://xemu.app/titles/";
16+
static constexpr char base_issue_url[] =
17+
"https://github.com/xemu-project/xemu/issues/new?template=";
18+
static constexpr char title_issue_template[] = "title-issue.yml";
19+
20+
static std::string BuildTitleInformation(struct xbe *xbe)
21+
{
22+
std::string ret = base_compatibility_url;
23+
24+
char title_id_buffer[32];
25+
snprintf(title_id_buffer, sizeof(title_id_buffer), "%x",
26+
xbe->cert->m_titleid);
27+
ret += title_id_buffer;
28+
29+
ret += "/";
30+
31+
char *xbe_title_name = g_utf16_to_utf8(xbe->cert->m_title_name,
32+
std::size(xbe->cert->m_title_name),
33+
nullptr, nullptr, nullptr);
34+
if (xbe_title_name) {
35+
ret += "#";
36+
ret += xbe_title_name;
37+
g_free(xbe_title_name);
38+
}
39+
ret += "\n";
40+
41+
return ret;
42+
}
43+
44+
static std::string BuildXemuInformation()
45+
{
46+
std::string ret = "* Version: ";
47+
ret += xemu_version;
48+
ret += "\n* Branch: ";
49+
ret += xemu_branch;
50+
ret += "\n* Commit: ";
51+
ret += xemu_commit;
52+
ret += "\n* Date: ";
53+
ret += xemu_date;
54+
ret += "\n\n";
55+
return ret;
56+
}
57+
58+
static std::string BuildSystemInformation()
59+
{
60+
std::string ret = "OS Info:\n* Platform: ";
61+
ret += xemu_get_os_platform();
62+
ret += "\n* Version: ";
63+
ret += xemu_get_os_info();
64+
ret += "\n";
65+
66+
ret += "CPU: ";
67+
ret += xemu_get_cpu_info();
68+
ret += "\n";
69+
70+
ret += "GPU Info:\n* Vendor: ";
71+
ret += (const char *)glGetString(GL_VENDOR);
72+
ret += "\n* Renderer: ";
73+
ret += (const char *)glGetString(GL_RENDERER);
74+
ret += "\n* GL Version: ";
75+
ret += (const char *)glGetString(GL_VERSION);
76+
ret += "\n* GLSL Version: ";
77+
ret += (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
78+
ret += "\n";
79+
80+
return ret;
81+
}
82+
83+
static std::string BuildAdditionalInformation()
84+
{
85+
char buf[64];
86+
snprintf(buf, sizeof(buf), "* Resolution scale: %dx\n",
87+
nv2a_get_surface_scale_factor());
88+
89+
std::string ret = buf;
90+
91+
ret += "* Renderer backend: ";
92+
switch (g_config.display.renderer) {
93+
case CONFIG_DISPLAY_RENDERER_NULL:
94+
ret += "NULL";
95+
break;
96+
case CONFIG_DISPLAY_RENDERER_OPENGL:
97+
ret += "OpenGL";
98+
break;
99+
case CONFIG_DISPLAY_RENDERER_VULKAN:
100+
ret += "Vulkan";
101+
break;
102+
default:
103+
ret += "UNKNOWN - update ";
104+
ret += __FILE__;
105+
break;
106+
}
107+
ret += "\n";
108+
109+
ret += "* Realtime DSP: ";
110+
ret += g_config.audio.use_dsp ? "ON" : "OFF";
111+
ret += "\n";
112+
113+
ret += "* System memory: ";
114+
switch (g_config.sys.mem_limit) {
115+
case CONFIG_SYS_MEM_LIMIT_64:
116+
ret += "64MiB";
117+
break;
118+
case CONFIG_SYS_MEM_LIMIT_128:
119+
ret += "128MiB";
120+
break;
121+
default:
122+
ret += "UNKNOWN - update ";
123+
ret += __FILE__;
124+
break;
125+
}
126+
ret += "\n";
127+
128+
ret += "* AV pack: ";
129+
switch (g_config.sys.avpack) {
130+
case CONFIG_SYS_AVPACK_SCART:
131+
ret += "SCART";
132+
break;
133+
case CONFIG_SYS_AVPACK_HDTV:
134+
ret += "HDTV";
135+
break;
136+
case CONFIG_SYS_AVPACK_VGA:
137+
ret += "VGA";
138+
break;
139+
case CONFIG_SYS_AVPACK_RFU:
140+
ret += "RFU";
141+
break;
142+
case CONFIG_SYS_AVPACK_SVIDEO:
143+
ret += "SVIDEO";
144+
break;
145+
case CONFIG_SYS_AVPACK_COMPOSITE:
146+
ret += "Composite";
147+
break;
148+
case CONFIG_SYS_AVPACK_NONE:
149+
ret += "None";
150+
break;
151+
default:
152+
ret += "UNKNOWN - update ";
153+
ret += __FILE__;
154+
break;
155+
}
156+
157+
return ret;
158+
}
159+
160+
static std::string BuildGitHubTitleIssueURL(struct xbe *xbe)
161+
{
162+
std::string ret = base_issue_url;
163+
ret += title_issue_template;
164+
165+
if (!ensure_libcurl_initialized(nullptr)) {
166+
fprintf(stderr, "Failed to initialize libcurl\n");
167+
return ret;
168+
}
169+
170+
CURL *curl = curl_easy_init();
171+
if (!curl) {
172+
fprintf(stderr, "Failed to initialize libcurl\n");
173+
return ret;
174+
}
175+
176+
{
177+
ret += "&game-title=";
178+
auto info = BuildTitleInformation(xbe);
179+
char *escaped_value =
180+
curl_easy_escape(curl, info.c_str(), info.length());
181+
ret += escaped_value;
182+
curl_free(escaped_value);
183+
}
184+
185+
{
186+
ret += "&xemu-version=";
187+
auto info = BuildXemuInformation();
188+
char *escaped_value =
189+
curl_easy_escape(curl, info.c_str(), info.length());
190+
ret += escaped_value;
191+
curl_free(escaped_value);
192+
}
193+
194+
{
195+
ret += "&system-information=";
196+
auto info = BuildSystemInformation();
197+
char *escaped_value =
198+
curl_easy_escape(curl, info.c_str(), info.length());
199+
ret += escaped_value;
200+
curl_free(escaped_value);
201+
}
202+
203+
{
204+
ret += "&additional-context=";
205+
auto info = BuildAdditionalInformation();
206+
char *escaped_value =
207+
curl_easy_escape(curl, info.c_str(), info.length());
208+
ret += escaped_value;
209+
curl_free(escaped_value);
210+
}
211+
212+
curl_easy_cleanup(curl);
213+
214+
return ret;
215+
}
216+
217+
void ShowReportGitHubIssueMenuItem()
218+
{
219+
struct xbe *xbe = xemu_get_xbe_info();
220+
if (!xbe) {
221+
return;
222+
}
223+
224+
if (ImGui::MenuItem("Report GitHub Title Issue...", NULL)) {
225+
xemu_open_web_browser(BuildGitHubTitleIssueURL(xbe).c_str());
226+
}
227+
}

ui/xui/github-issue.hh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// xemu User Interface
3+
//
4+
// Copyright (C) 2020-2025 Matt Borgerson
5+
//
6+
// This program is free software; you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation; either version 2 of the License, or
9+
// (at your option) any later version.
10+
//
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
//
19+
#pragma once
20+
21+
/**
22+
* Displays an ImGui MenuItem that will open a web browser with a partially
23+
* populated "Title Issue" template if an identified title is loaded. Otherwise
24+
* does nothing.
25+
*/
26+
void ShowReportGitHubIssueMenuItem();

ui/xui/menubar.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "debug.hh"
2727
#include "actions.hh"
2828
#include "compat.hh"
29+
#include "github-issue.hh"
2930
#include "update.hh"
3031
#include "../xemu-os-utils.h"
3132

@@ -236,6 +237,8 @@ void ShowMainMenu()
236237

237238
ImGui::MenuItem("Report Compatibility...", NULL,
238239
&compatibility_reporter_window.is_open);
240+
241+
ShowReportGitHubIssueMenuItem();
239242
#if defined(_WIN32)
240243
ImGui::MenuItem("Check for Updates...", NULL, &update_window.is_open);
241244
#endif

ui/xui/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ xemu_ss.add(files(
44
'compat.cc',
55
'debug.cc',
66
'font-manager.cc',
7+
'github-issue.cc',
78
'gl-helpers.cc',
89
'input-manager.cc',
910
'main-menu.cc',

util/http.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
static bool libcurl_init_called = false;
3131
static bool libcurl_init_success = false;
3232

33-
static bool ensure_libcurl_initialized(Error **errp)
33+
bool ensure_libcurl_initialized(Error **errp)
3434
{
3535
if (!libcurl_init_called) {
3636
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);

0 commit comments

Comments
 (0)