|
7 | 7 |
|
8 | 8 | #include "gui/dialogs/file_dialog.h" |
9 | 9 |
|
10 | | -#ifdef _WIN32 |
11 | 10 | // clang-format off |
| 11 | +#ifdef _WIN32 |
12 | 12 | #define WIN32_LEAN_AND_MEAN |
13 | 13 | #include <windows.h> |
14 | 14 | #include <commdlg.h> |
15 | 15 | #endif |
16 | 16 |
|
17 | 17 | #ifdef __APPLE__ |
18 | 18 | #include <TargetConditionals.h> |
19 | | -#include <cstdio> |
20 | 19 | #include <fcntl.h> |
21 | 20 | #include <sys/wait.h> |
22 | 21 | #include <unistd.h> |
| 22 | + |
| 23 | +#include <cstdio> |
23 | 24 | #endif |
24 | 25 |
|
25 | 26 | #ifndef _WIN32 |
26 | 27 | #include <sys/wait.h> |
27 | 28 | #endif |
| 29 | +// clang-format on |
28 | 30 |
|
29 | 31 | namespace Amplitron { |
30 | 32 |
|
31 | 33 | #ifdef AMPLITRON_HEADLESS |
32 | 34 | static std::string s_mock_open_path = ""; |
33 | 35 |
|
34 | | -void set_mock_open_dialog_path(const std::string &path) { |
35 | | - s_mock_open_path = path; |
36 | | -} |
| 36 | +void set_mock_open_dialog_path(const std::string &path) { s_mock_open_path = path; } |
37 | 37 |
|
38 | | -std::string show_open_dialog(const std::string &, const std::string &, |
39 | | - const std::string &) { |
40 | | - return s_mock_open_path; |
| 38 | +std::string show_open_dialog(const std::string &, const std::string &, const std::string &) { |
| 39 | + return s_mock_open_path; |
41 | 40 | } |
42 | 41 | #else |
43 | 42 |
|
| 43 | +// clang-format off |
44 | 44 | #ifdef _WIN32 |
45 | | -std::string show_open_dialog(const std::string &title, |
46 | | - const std::string &filter_desc, |
47 | | - const std::string &filter_ext) { |
48 | | - char filename[MAX_PATH] = ""; |
49 | | - |
50 | | - char filter[256]; |
51 | | - std::memset(filter, 0, sizeof(filter)); |
52 | | - int pos = 0; |
53 | | - pos += snprintf(filter + pos, 256 - pos, "%s (*.%s)", filter_desc.c_str(), |
54 | | - filter_ext.c_str()); |
55 | | - pos++; |
56 | | - pos += snprintf(filter + pos, 256 - pos, "*.%s", filter_ext.c_str()); |
57 | | - pos++; |
58 | | - pos += snprintf(filter + pos, 256 - pos, "All Files (*.*)"); |
59 | | - pos++; |
60 | | - pos += snprintf(filter + pos, 256 - pos, "*.*"); |
61 | | - |
62 | | - OPENFILENAMEA ofn; |
63 | | - std::memset(&ofn, 0, sizeof(ofn)); |
64 | | - ofn.lStructSize = sizeof(ofn); |
65 | | - ofn.hwndOwner = NULL; |
66 | | - ofn.lpstrFilter = filter; |
67 | | - ofn.lpstrFile = filename; |
68 | | - ofn.nMaxFile = MAX_PATH; |
69 | | - ofn.lpstrTitle = title.c_str(); |
70 | | - ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; |
71 | | - |
72 | | - if (GetOpenFileNameA(&ofn)) { |
73 | | - return std::string(filename); |
74 | | - } |
75 | | - return ""; |
| 45 | +std::string show_open_dialog(const std::string& title, const std::string& filter_desc, |
| 46 | + const std::string& filter_ext) { |
| 47 | + char filename[MAX_PATH] = ""; |
| 48 | + |
| 49 | + char filter[256]; |
| 50 | + std::memset(filter, 0, sizeof(filter)); |
| 51 | + int pos = 0; |
| 52 | + pos += snprintf(filter + pos, 256 - pos, "%s (*.%s)", filter_desc.c_str(), filter_ext.c_str()); |
| 53 | + pos++; |
| 54 | + pos += snprintf(filter + pos, 256 - pos, "*.%s", filter_ext.c_str()); |
| 55 | + pos++; |
| 56 | + pos += snprintf(filter + pos, 256 - pos, "All Files (*.*)"); |
| 57 | + pos++; |
| 58 | + pos += snprintf(filter + pos, 256 - pos, "*.*"); |
| 59 | + |
| 60 | + OPENFILENAMEA ofn; |
| 61 | + std::memset(&ofn, 0, sizeof(ofn)); |
| 62 | + ofn.lStructSize = sizeof(ofn); |
| 63 | + ofn.hwndOwner = NULL; |
| 64 | + ofn.lpstrFilter = filter; |
| 65 | + ofn.lpstrFile = filename; |
| 66 | + ofn.nMaxFile = MAX_PATH; |
| 67 | + ofn.lpstrTitle = title.c_str(); |
| 68 | + ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; |
| 69 | + |
| 70 | + if (GetOpenFileNameA(&ofn)) { |
| 71 | + return std::string(filename); |
| 72 | + } |
| 73 | + return ""; |
76 | 74 | } |
77 | 75 |
|
78 | 76 | #elif defined(__APPLE__) && !TARGET_OS_IOS |
79 | | -std::string show_open_dialog(const std::string &title, |
80 | | - const std::string & /*filter_desc*/, |
81 | | - const std::string &filter_ext) { |
82 | | - // Sanitize title and filter_ext for AppleScript |
83 | | - std::string safe_title; |
84 | | - for (char c : title) { |
85 | | - if (c == '\\') { |
86 | | - safe_title += "\\\\"; |
87 | | - } else if (c == '"') { |
88 | | - safe_title += "\\\""; |
89 | | - } else { |
90 | | - safe_title += c; |
| 77 | +std::string show_open_dialog(const std::string& title, const std::string& /*filter_desc*/, |
| 78 | + const std::string& filter_ext) { |
| 79 | + // Sanitize title and filter_ext for AppleScript |
| 80 | + std::string safe_title; |
| 81 | + for (char c : title) { |
| 82 | + if (c == '\\') { |
| 83 | + safe_title += "\\\\"; |
| 84 | + } else if (c == '"') { |
| 85 | + safe_title += "\\\""; |
| 86 | + } else { |
| 87 | + safe_title += c; |
| 88 | + } |
91 | 89 | } |
92 | | - } |
93 | | - |
94 | | - std::string safe_ext; |
95 | | - for (char c : filter_ext) { |
96 | | - if (c == '\\') { |
97 | | - safe_ext += "\\\\"; |
98 | | - } else if (c == '"') { |
99 | | - safe_ext += "\\\""; |
100 | | - } else { |
101 | | - safe_ext += c; |
| 90 | + |
| 91 | + std::string safe_ext; |
| 92 | + for (char c : filter_ext) { |
| 93 | + if (c == '\\') { |
| 94 | + safe_ext += "\\\\"; |
| 95 | + } else if (c == '"') { |
| 96 | + safe_ext += "\\\""; |
| 97 | + } else { |
| 98 | + safe_ext += c; |
| 99 | + } |
102 | 100 | } |
103 | | - } |
104 | 101 |
|
105 | | - std::string script = "POSIX path of (choose file of type {\"" + safe_ext + |
106 | | - "\"} with prompt \"" + safe_title + "\")"; |
| 102 | + std::string script = "POSIX path of (choose file of type {\"" + safe_ext + |
| 103 | + "\"} with prompt \"" + safe_title + "\")"; |
107 | 104 |
|
108 | | - // Use fork+exec to invoke osascript directly |
109 | | - int pipefd[2]; |
110 | | - if (pipe(pipefd) != 0) |
111 | | - return ""; |
| 105 | + // Use fork+exec to invoke osascript directly |
| 106 | + int pipefd[2]; |
| 107 | + if (pipe(pipefd) != 0) return ""; |
112 | 108 |
|
113 | | - pid_t pid = fork(); |
114 | | - if (pid < 0) { |
115 | | - close(pipefd[0]); |
116 | | - close(pipefd[1]); |
117 | | - return ""; |
118 | | - } |
| 109 | + pid_t pid = fork(); |
| 110 | + if (pid < 0) { |
| 111 | + close(pipefd[0]); |
| 112 | + close(pipefd[1]); |
| 113 | + return ""; |
| 114 | + } |
119 | 115 |
|
120 | | - if (pid == 0) { |
121 | | - close(pipefd[0]); |
122 | | - dup2(pipefd[1], STDOUT_FILENO); |
123 | | - close(pipefd[1]); |
124 | | - int devnull = open("/dev/null", O_WRONLY); |
125 | | - if (devnull >= 0) { |
126 | | - dup2(devnull, STDERR_FILENO); |
127 | | - close(devnull); |
| 116 | + if (pid == 0) { |
| 117 | + close(pipefd[0]); |
| 118 | + dup2(pipefd[1], STDOUT_FILENO); |
| 119 | + close(pipefd[1]); |
| 120 | + int devnull = open("/dev/null", O_WRONLY); |
| 121 | + if (devnull >= 0) { |
| 122 | + dup2(devnull, STDERR_FILENO); |
| 123 | + close(devnull); |
| 124 | + } |
| 125 | + execl("/usr/bin/osascript", "osascript", "-e", script.c_str(), nullptr); |
| 126 | + _exit(1); |
128 | 127 | } |
129 | | - execl("/usr/bin/osascript", "osascript", "-e", script.c_str(), nullptr); |
130 | | - _exit(1); |
131 | | - } |
132 | 128 |
|
133 | | - close(pipefd[1]); |
134 | | - char buf[1024]; |
135 | | - std::string result; |
136 | | - ssize_t n; |
137 | | - while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) |
138 | | - result.append(buf, static_cast<size_t>(n)); |
139 | | - close(pipefd[0]); |
| 129 | + close(pipefd[1]); |
| 130 | + char buf[1024]; |
| 131 | + std::string result; |
| 132 | + ssize_t n; |
| 133 | + while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) result.append(buf, static_cast<size_t>(n)); |
| 134 | + close(pipefd[0]); |
140 | 135 |
|
141 | | - int status = 0; |
142 | | - waitpid(pid, &status, 0); |
| 136 | + int status = 0; |
| 137 | + waitpid(pid, &status, 0); |
143 | 138 |
|
144 | | - while (!result.empty() && (result.back() == '\n' || result.back() == '\r')) |
145 | | - result.pop_back(); |
| 139 | + while (!result.empty() && (result.back() == '\n' || result.back() == '\r')) result.pop_back(); |
146 | 140 |
|
147 | | - return result; |
| 141 | + return result; |
148 | 142 | } |
149 | 143 |
|
150 | | -#else // Linux |
151 | | -std::string show_open_dialog(const std::string &title, |
152 | | - const std::string &filter_desc, |
153 | | - const std::string &filter_ext) { |
154 | | - // Escape single quotes for shell |
155 | | - auto escape_single_quotes = [](const std::string &s) { |
| 144 | +#else // Linux |
| 145 | +std::string show_open_dialog(const std::string& title, const std::string& filter_desc, |
| 146 | + const std::string& filter_ext) { |
| 147 | + // Escape single quotes for shell |
| 148 | + auto escape_single_quotes = [](const std::string& s) { |
| 149 | + std::string result; |
| 150 | + for (char c : s) { |
| 151 | + if (c == '\'') { |
| 152 | + result += "'\\''"; |
| 153 | + } else { |
| 154 | + result += c; |
| 155 | + } |
| 156 | + } |
| 157 | + return result; |
| 158 | + }; |
| 159 | + |
| 160 | + std::string safe_title = escape_single_quotes(title); |
| 161 | + std::string safe_desc = escape_single_quotes(filter_desc); |
| 162 | + std::string safe_ext = escape_single_quotes(filter_ext); |
| 163 | + |
| 164 | + std::string cmd = |
| 165 | + "zenity --file-selection " |
| 166 | + "--title='" + |
| 167 | + safe_title + |
| 168 | + "' " |
| 169 | + "--file-filter='" + |
| 170 | + safe_desc + " (*." + safe_ext + ")|*." + safe_ext + |
| 171 | + "' " |
| 172 | + "--file-filter='All Files (*)|*' 2>/dev/null"; |
| 173 | + |
| 174 | + FILE* pipe = popen(cmd.c_str(), "r"); |
| 175 | + if (!pipe) return ""; |
| 176 | + |
| 177 | + char buf[1024]; |
156 | 178 | std::string result; |
157 | | - for (char c : s) { |
158 | | - if (c == '\'') { |
159 | | - result += "'\\''"; |
160 | | - } else { |
161 | | - result += c; |
162 | | - } |
163 | | - } |
164 | | - return result; |
165 | | - }; |
166 | | - |
167 | | - std::string safe_title = escape_single_quotes(title); |
168 | | - std::string safe_desc = escape_single_quotes(filter_desc); |
169 | | - std::string safe_ext = escape_single_quotes(filter_ext); |
170 | | - |
171 | | - std::string cmd = "zenity --file-selection " |
172 | | - "--title='" + |
173 | | - safe_title + |
174 | | - "' " |
175 | | - "--file-filter='" + |
176 | | - safe_desc + " (*." + safe_ext + ")|*." + safe_ext + |
177 | | - "' " |
178 | | - "--file-filter='All Files (*)|*' 2>/dev/null"; |
179 | | - |
180 | | - FILE *pipe = popen(cmd.c_str(), "r"); |
181 | | - if (!pipe) |
182 | | - return ""; |
183 | | - |
184 | | - char buf[1024]; |
185 | | - std::string result; |
186 | | - while (fgets(buf, sizeof(buf), pipe)) { |
187 | | - result += buf; |
188 | | - } |
189 | | - int wait_status = pclose(pipe); |
190 | | - |
191 | | - if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) != 0) { |
192 | | - cmd = "kdialog --getopenfilename ~/ '*." + safe_ext + "|" + safe_desc + |
193 | | - "' " |
194 | | - "--title '" + |
195 | | - safe_title + "' 2>/dev/null"; |
196 | | - pipe = popen(cmd.c_str(), "r"); |
197 | | - if (!pipe) |
198 | | - return ""; |
199 | | - result.clear(); |
200 | 179 | while (fgets(buf, sizeof(buf), pipe)) { |
201 | | - result += buf; |
| 180 | + result += buf; |
| 181 | + } |
| 182 | + int wait_status = pclose(pipe); |
| 183 | + |
| 184 | + if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) != 0) { |
| 185 | + cmd = "kdialog --getopenfilename ~/ '*." + safe_ext + "|" + safe_desc + |
| 186 | + "' " |
| 187 | + "--title '" + |
| 188 | + safe_title + "' 2>/dev/null"; |
| 189 | + pipe = popen(cmd.c_str(), "r"); |
| 190 | + if (!pipe) return ""; |
| 191 | + result.clear(); |
| 192 | + while (fgets(buf, sizeof(buf), pipe)) { |
| 193 | + result += buf; |
| 194 | + } |
| 195 | + pclose(pipe); |
202 | 196 | } |
203 | | - pclose(pipe); |
204 | | - } |
205 | 197 |
|
206 | | - while (!result.empty() && (result.back() == '\n' || result.back() == '\r')) |
207 | | - result.pop_back(); |
| 198 | + while (!result.empty() && (result.back() == '\n' || result.back() == '\r')) result.pop_back(); |
208 | 199 |
|
209 | | - return result; |
| 200 | + return result; |
210 | 201 | } |
211 | 202 | #endif |
| 203 | +// clang-format on |
212 | 204 |
|
213 | 205 | #endif // AMPLITRON_HEADLESS |
214 | 206 |
|
|
0 commit comments