1 /******************************************************************************
2 Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
3 Copyright (C) 2014 by Zachary Lund <admin@computerquip.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 ******************************************************************************/
18
19 #include "obs-internal.h"
20 #include "obs-nix.h"
21 #include "obs-nix-platform.h"
22 #include "obs-nix-x11.h"
23
24 #ifdef ENABLE_WAYLAND
25 #include "obs-nix-wayland.h"
26 #endif
27
28 #if defined(__FreeBSD__)
29 #define _GNU_SOURCE
30 #endif
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #if defined(__FreeBSD__) || defined(__OpenBSD__)
35 #include <sys/sysctl.h>
36 #endif
37 #if !defined(__OpenBSD__)
38 #include <sys/sysinfo.h>
39 #endif
40 #include <sys/utsname.h>
41 #include <inttypes.h>
42
get_module_extension(void)43 const char *get_module_extension(void)
44 {
45 return ".so";
46 }
47
48 #ifdef __LP64__
49 #define BIT_STRING "64bit"
50 #else
51 #define BIT_STRING "32bit"
52 #endif
53
54 #define FLATPAK_PLUGIN_PATH "/app/plugins"
55
56 static const char *module_bin[] = {
57 "../../obs-plugins/" BIT_STRING,
58 OBS_INSTALL_PREFIX "/" OBS_PLUGIN_DESTINATION,
59 FLATPAK_PLUGIN_PATH "/" OBS_PLUGIN_DESTINATION,
60 };
61
62 static const char *module_data[] = {
63 OBS_DATA_PATH "/obs-plugins/%module%",
64 OBS_INSTALL_DATA_PATH "/obs-plugins/%module%",
65 FLATPAK_PLUGIN_PATH "/share/obs/obs-plugins/%module%",
66 };
67
68 static const int module_patterns_size =
69 sizeof(module_bin) / sizeof(module_bin[0]);
70
71 static const struct obs_nix_hotkeys_vtable *hotkeys_vtable = NULL;
72
add_default_module_paths(void)73 void add_default_module_paths(void)
74 {
75 for (int i = 0; i < module_patterns_size; i++)
76 obs_add_module_path(module_bin[i], module_data[i]);
77 }
78
79 /*
80 * /usr/local/share/libobs
81 * /usr/share/libobs
82 */
find_libobs_data_file(const char * file)83 char *find_libobs_data_file(const char *file)
84 {
85 struct dstr output;
86 dstr_init(&output);
87
88 if (check_path(file, OBS_DATA_PATH "/libobs/", &output))
89 return output.array;
90
91 if (OBS_INSTALL_PREFIX[0] != 0) {
92 if (check_path(file, OBS_INSTALL_DATA_PATH "/libobs/", &output))
93 return output.array;
94 }
95
96 dstr_free(&output);
97 return NULL;
98 }
99
log_processor_cores(void)100 static void log_processor_cores(void)
101 {
102 blog(LOG_INFO, "Physical Cores: %d, Logical Cores: %d",
103 os_get_physical_cores(), os_get_logical_cores());
104 }
105
106 #if defined(__linux__)
log_processor_info(void)107 static void log_processor_info(void)
108 {
109 int physical_id = -1;
110 int last_physical_id = -1;
111 char *line = NULL;
112 size_t linecap = 0;
113
114 FILE *fp;
115 struct dstr proc_name;
116 struct dstr proc_speed;
117
118 fp = fopen("/proc/cpuinfo", "r");
119 if (!fp)
120 return;
121
122 dstr_init(&proc_name);
123 dstr_init(&proc_speed);
124
125 while (getline(&line, &linecap, fp) != -1) {
126 if (!strncmp(line, "model name", 10)) {
127 char *start = strchr(line, ':');
128 if (!start || *(++start) == '\0')
129 continue;
130
131 dstr_copy(&proc_name, start);
132 dstr_resize(&proc_name, proc_name.len - 1);
133 dstr_depad(&proc_name);
134 }
135
136 if (!strncmp(line, "physical id", 11)) {
137 char *start = strchr(line, ':');
138 if (!start || *(++start) == '\0')
139 continue;
140
141 physical_id = atoi(start);
142 }
143
144 if (!strncmp(line, "cpu MHz", 7)) {
145 char *start = strchr(line, ':');
146 if (!start || *(++start) == '\0')
147 continue;
148
149 dstr_copy(&proc_speed, start);
150 dstr_resize(&proc_speed, proc_speed.len - 1);
151 dstr_depad(&proc_speed);
152 }
153
154 if (*line == '\n' && physical_id != last_physical_id) {
155 last_physical_id = physical_id;
156 blog(LOG_INFO, "CPU Name: %s", proc_name.array);
157 blog(LOG_INFO, "CPU Speed: %sMHz", proc_speed.array);
158 }
159 }
160
161 fclose(fp);
162 dstr_free(&proc_name);
163 dstr_free(&proc_speed);
164 free(line);
165 }
166 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
log_processor_speed(void)167 static void log_processor_speed(void)
168 {
169 #ifndef __OpenBSD__
170 char *line = NULL;
171 size_t linecap = 0;
172 FILE *fp;
173 struct dstr proc_speed;
174
175 fp = fopen("/var/run/dmesg.boot", "r");
176 if (!fp) {
177 blog(LOG_INFO, "CPU: Missing /var/run/dmesg.boot !");
178 return;
179 }
180
181 dstr_init(&proc_speed);
182
183 while (getline(&line, &linecap, fp) != -1) {
184 if (!strncmp(line, "CPU: ", 5)) {
185 char *start = strrchr(line, '(');
186 if (!start || *(++start) == '\0')
187 continue;
188
189 size_t len = strcspn(start, "-");
190 dstr_ncopy(&proc_speed, start, len);
191 }
192 }
193
194 blog(LOG_INFO, "CPU Speed: %sMHz", proc_speed.array);
195
196 fclose(fp);
197 dstr_free(&proc_speed);
198 free(line);
199 #endif
200 }
201
log_processor_name(void)202 static void log_processor_name(void)
203 {
204 int mib[2];
205 size_t len;
206 char *proc;
207
208 mib[0] = CTL_HW;
209 mib[1] = HW_MODEL;
210
211 sysctl(mib, 2, NULL, &len, NULL, 0);
212 proc = bmalloc(len);
213 if (!proc)
214 return;
215
216 sysctl(mib, 2, proc, &len, NULL, 0);
217 blog(LOG_INFO, "CPU Name: %s", proc);
218
219 bfree(proc);
220 }
221
log_processor_info(void)222 static void log_processor_info(void)
223 {
224 log_processor_name();
225 log_processor_speed();
226 }
227 #endif
228
log_memory_info(void)229 static void log_memory_info(void)
230 {
231 #if defined(__OpenBSD__)
232 int mib[2];
233 size_t len;
234 int64_t mem;
235
236 mib[0] = CTL_HW;
237 mib[1] = HW_PHYSMEM64;
238 len = sizeof(mem);
239
240 if (sysctl(mib, 2, &mem, &len, NULL, 0) >= 0)
241 blog(LOG_INFO, "Physical Memory: %" PRIi64 "MB Total",
242 mem / 1024 / 1024);
243 #else
244 struct sysinfo info;
245 if (sysinfo(&info) < 0)
246 return;
247
248 blog(LOG_INFO,
249 "Physical Memory: %" PRIu64 "MB Total, %" PRIu64 "MB Free",
250 (uint64_t)info.totalram * info.mem_unit / 1024 / 1024,
251 ((uint64_t)info.freeram + (uint64_t)info.bufferram) *
252 info.mem_unit / 1024 / 1024);
253 #endif
254 }
255
log_kernel_version(void)256 static void log_kernel_version(void)
257 {
258 struct utsname info;
259 if (uname(&info) < 0)
260 return;
261
262 blog(LOG_INFO, "Kernel Version: %s %s", info.sysname, info.release);
263 }
264
265 #if defined(__linux__)
log_distribution_info(void)266 static void log_distribution_info(void)
267 {
268 FILE *fp;
269 char *line = NULL;
270 size_t linecap = 0;
271 struct dstr distro;
272 struct dstr version;
273
274 fp = fopen("/etc/os-release", "r");
275 if (!fp) {
276 blog(LOG_INFO, "Distribution: Missing /etc/os-release !");
277 return;
278 }
279
280 dstr_init_copy(&distro, "Unknown");
281 dstr_init_copy(&version, "Unknown");
282
283 while (getline(&line, &linecap, fp) != -1) {
284 if (!strncmp(line, "NAME", 4)) {
285 char *start = strchr(line, '=');
286 if (!start || *(++start) == '\0')
287 continue;
288 dstr_copy(&distro, start);
289 dstr_resize(&distro, distro.len - 1);
290 }
291
292 if (!strncmp(line, "VERSION_ID", 10)) {
293 char *start = strchr(line, '=');
294 if (!start || *(++start) == '\0')
295 continue;
296 dstr_copy(&version, start);
297 dstr_resize(&version, version.len - 1);
298 }
299 }
300
301 blog(LOG_INFO, "Distribution: %s %s", distro.array, version.array);
302
303 fclose(fp);
304 dstr_free(&version);
305 dstr_free(&distro);
306 free(line);
307 }
308
log_desktop_session_info(void)309 static void log_desktop_session_info(void)
310 {
311 char *session_ptr = getenv("XDG_SESSION_TYPE");
312 if (session_ptr) {
313 blog(LOG_INFO, "Session Type: %s", session_ptr);
314 }
315 }
316 #endif
317
log_system_info(void)318 void log_system_info(void)
319 {
320 #if defined(__linux__) || defined(__FreeBSD__)
321 log_processor_info();
322 #endif
323 log_processor_cores();
324 log_memory_info();
325 log_kernel_version();
326 #if defined(__linux__)
327 log_distribution_info();
328 log_desktop_session_info();
329 #endif
330 switch (obs_get_nix_platform()) {
331 case OBS_NIX_PLATFORM_X11_GLX:
332 case OBS_NIX_PLATFORM_X11_EGL:
333 obs_nix_x11_log_info();
334 break;
335 #ifdef ENABLE_WAYLAND
336 case OBS_NIX_PLATFORM_WAYLAND:
337 break;
338 #endif
339 }
340 }
341
obs_hotkeys_platform_init(struct obs_core_hotkeys * hotkeys)342 bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
343 {
344 switch (obs_get_nix_platform()) {
345 case OBS_NIX_PLATFORM_X11_GLX:
346 case OBS_NIX_PLATFORM_X11_EGL:
347 hotkeys_vtable = obs_nix_x11_get_hotkeys_vtable();
348 break;
349 #ifdef ENABLE_WAYLAND
350 case OBS_NIX_PLATFORM_WAYLAND:
351 hotkeys_vtable = obs_nix_wayland_get_hotkeys_vtable();
352 break;
353 #endif
354 }
355
356 return hotkeys_vtable->init(hotkeys);
357 }
358
obs_hotkeys_platform_free(struct obs_core_hotkeys * hotkeys)359 void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
360 {
361 hotkeys_vtable->free(hotkeys);
362 hotkeys_vtable = NULL;
363 }
364
obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t * context,obs_key_t key)365 bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
366 obs_key_t key)
367 {
368 return hotkeys_vtable->is_pressed(context, key);
369 }
370
obs_key_to_str(obs_key_t key,struct dstr * dstr)371 void obs_key_to_str(obs_key_t key, struct dstr *dstr)
372 {
373 return hotkeys_vtable->key_to_str(key, dstr);
374 }
375
obs_key_from_virtual_key(int sym)376 obs_key_t obs_key_from_virtual_key(int sym)
377 {
378 return hotkeys_vtable->key_from_virtual_key(sym);
379 }
380
obs_key_to_virtual_key(obs_key_t key)381 int obs_key_to_virtual_key(obs_key_t key)
382 {
383 return hotkeys_vtable->key_to_virtual_key(key);
384 }
385
add_combo_key(obs_key_t key,struct dstr * str)386 static inline void add_combo_key(obs_key_t key, struct dstr *str)
387 {
388 struct dstr key_str = {0};
389
390 obs_key_to_str(key, &key_str);
391
392 if (!dstr_is_empty(&key_str)) {
393 if (!dstr_is_empty(str)) {
394 dstr_cat(str, " + ");
395 }
396 dstr_cat_dstr(str, &key_str);
397 }
398
399 dstr_free(&key_str);
400 }
401
obs_key_combination_to_str(obs_key_combination_t combination,struct dstr * str)402 void obs_key_combination_to_str(obs_key_combination_t combination,
403 struct dstr *str)
404 {
405 if ((combination.modifiers & INTERACT_CONTROL_KEY) != 0) {
406 add_combo_key(OBS_KEY_CONTROL, str);
407 }
408 if ((combination.modifiers & INTERACT_COMMAND_KEY) != 0) {
409 add_combo_key(OBS_KEY_META, str);
410 }
411 if ((combination.modifiers & INTERACT_ALT_KEY) != 0) {
412 add_combo_key(OBS_KEY_ALT, str);
413 }
414 if ((combination.modifiers & INTERACT_SHIFT_KEY) != 0) {
415 add_combo_key(OBS_KEY_SHIFT, str);
416 }
417 if (combination.key != OBS_KEY_NONE) {
418 add_combo_key(combination.key, str);
419 }
420 }
421