mcap/src/base/platform/platform_linux.jai

152 lines
5.0 KiB
Plaintext

platform_load_platform_information :: () {
}
platform_get_path_program_data :: inline () -> string {
return XDG.get_path(.DATA_HOME);
}
platform_get_path_config_data :: inline () -> string {
return XDG.get_path(.CONFIG_HOME);
}
// $TMPDIR, else /tmp, without a separator at the end. Temp.
platform_temporary_folder :: () -> string {
folder := posix_getenv("TMPDIR");
if !folder return "/tmp";
return trim_right(copy_string(folder,, temp), "/");
}
// A tag such as ja-JP from the locale variables, or "". Temp.
platform_preferred_language :: () -> string {
for string.["LC_ALL", "LC_MESSAGES", "LANG"] {
value := posix_getenv(it);
if !value || value == "C" || value == "POSIX" continue;
tag := copy_string(value,, temp);
dot := find_index_from_left(tag, #char "."); // ja_JP.UTF-8
if dot >= 0 tag.count = dot;
return replace(tag, "_", "-",, temp);
}
return "";
}
// Temp. Noto Sans CJK's collection holds every script: JP, KR, SC, TC in that order.
platform_cjk_font_candidates :: () -> [] Cjk_Font {
list: [..] Cjk_Font;
list.allocator = temp;
for folder: string.["/usr/share/fonts/opentype/noto", "/usr/share/fonts/noto-cjk"] {
path := tprint("%/NotoSansCJK-Regular.ttc", folder);
cjk_candidate(*list, .JAPANESE, path, "Noto Sans CJK JP", face = 0);
cjk_candidate(*list, .KOREAN, path, "Noto Sans CJK KR", face = 1);
cjk_candidate(*list, .SIMPLIFIED, path, "Noto Sans CJK SC", face = 2);
cjk_candidate(*list, .TRADITIONAL, path, "Noto Sans CJK TC", face = 3);
}
return list;
}
// Wayland has no global hotkey API, and X11 key grabs are not implemented, so none are registered.
// A desktop's own shortcut settings can run the executable instead: a second launch brings the
// running instance forward over the IPC channel.
platform_apply_global_hotkeys :: (actions: [] Hotkey_Action) {
bound := false;
for actions if it.hotkey.binding_count bound = true;
if bound log("[hotkeys] Global hotkeys are not supported on Linux; [global_hotkeys] is ignored.");
}
platform_unregister_global_hotkeys :: () {}
// Resident and virtual sizes, and their peaks, from /proc/self/status.
platform_update_memory_usage_metrics :: () { using perf.memory_usage;
data, ok := read_entire_file("/proc/self/status", log_errors = false,, temp);
if !ok return;
kilobytes :: (data: string, key: string) -> s64 {
index := find_index_from_left(data, key);
if index < 0 return -1;
rest := slice(data, index + key.count, data.count - index - key.count);
value, ok := string_to_int(trim_left(rest));
return ifx ok then value else -1;
}
rss := kilobytes(data, "VmRSS:");
hwm := kilobytes(data, "VmHWM:");
size := kilobytes(data, "VmSize:");
peak := kilobytes(data, "VmPeak:");
if rss >= 0 working_set = rss * 1024;
if hwm >= 0 peak_working_set = hwm * 1024;
if size >= 0 virtual_memory = size * 1024;
if peak >= 0 peak_virtual_memory = peak * 1024;
}
linux_get_desktop_environment :: () -> Linux_Desktop_Environment {
push_allocator(temp);
result := to_string(SDL_getenv("XDG_CURRENT_DESKTOP"));
log("XDG_CURRENT_DESKTOP: %", result);
// Some desktops list several names, as in ubuntu:GNOME.
for name: split(to_lower_copy(result), ":") {
if name == {
case "xfce"; return .XFCE;
case "gnome"; return .GNOME;
case "kde"; return .KDE;
case "hyprland"; return .Hyprland;
case "sway"; return .sway;
case "unity"; return .Unity;
case "lxqt"; return .LXQt;
case "mate"; return .MATE;
}
}
return .UNKNOWN;
}
Linux_Desktop_Environment :: enum s32 {
UNKNOWN :: 0;
XFCE :: 1;
GNOME :: 2;
KDE :: 3;
Hyprland :: 4;
sway :: 5;
Unity :: 6;
LXQt :: 7;
MATE :: 8;
}
Linux_Display_Backend :: enum s32 {
X11 :: 0;
WAYLAND :: 1;
OTHER :: -1;
}
linux_get_SDL3_backend :: () -> Linux_Display_Backend {
driver := to_string(SDL_GetCurrentVideoDriver());
if driver == "x11"
return .X11;
if driver == "wayland"
return .WAYLAND;
return .OTHER;
}
linux_platform_setup :: () { using platform;
desktop_environment = linux_get_desktop_environment();
display_backend = linux_get_SDL3_backend();
log("[linux] Desktop environment: %, display backend: %.", desktop_environment, display_backend);
}
os_clear_unused_pages :: () {
log("[os_clear_unused_pages] Not implemented on Linux.");
}
platform_set_thread_affinity_all :: #bake_arguments platform_set_thread_affinity(affinity=.All);
platform_set_thread_affinity :: (thread: *Thread, affinity: CPUID_Type) {
}
XDG :: #import "XDG";
// Drops what the page cache holds of the file, so the next read comes from the disk (-cold). Clean
// pages go at once; pages not yet written back stay. False when it cannot be opened.
platform_evict_file_cache :: (path: string) -> bool {
fd := POSIX.open(temp_c_string(path), POSIX.O_RDONLY | POSIX.O_CLOEXEC);
if fd < 0 return false;
defer POSIX.close(fd);
return POSIX.posix_fadvise(fd, 0, 0, POSIX.POSIX_FADV_DONTNEED) == 0;
}