forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
@ -0,0 +1,41 @@
|
||||
#include "funcs.h"
|
||||
#include <kinc/display.h>
|
||||
|
||||
void kinc_display_init() {
|
||||
static bool display_initialized = false;
|
||||
if (display_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
kinc_linux_init_procs();
|
||||
procs.display_init();
|
||||
display_initialized = true;
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_display_available_mode(int display, int mode) {
|
||||
return procs.display_available_mode(display, mode);
|
||||
}
|
||||
|
||||
int kinc_display_count_available_modes(int display) {
|
||||
return procs.display_count_available_modes(display);
|
||||
}
|
||||
|
||||
bool kinc_display_available(int display) {
|
||||
return procs.display_available(display);
|
||||
}
|
||||
|
||||
const char *kinc_display_name(int display) {
|
||||
return procs.display_name(display);
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_display_current_mode(int display) {
|
||||
return procs.display_current_mode(display);
|
||||
}
|
||||
|
||||
int kinc_primary_display(void) {
|
||||
return procs.display_primary();
|
||||
}
|
||||
|
||||
int kinc_count_displays(void) {
|
||||
return procs.count_displays();
|
||||
}
|
67
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/funcs.h
Normal file
67
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/funcs.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/window.h>
|
||||
#ifdef KINC_EGL
|
||||
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
#ifdef KINC_VULKAN
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
struct linux_procs {
|
||||
bool (*handle_messages)(void);
|
||||
void (*shutdown)(void);
|
||||
|
||||
void (*display_init)(void);
|
||||
kinc_display_mode_t (*display_available_mode)(int display, int mode);
|
||||
int (*display_count_available_modes)(int display);
|
||||
bool (*display_available)(int display_index);
|
||||
const char *(*display_name)(int display_index);
|
||||
kinc_display_mode_t (*display_current_mode)(int display_index);
|
||||
int (*display_primary)(void);
|
||||
int (*count_displays)(void);
|
||||
|
||||
int (*window_create)(kinc_window_options_t *window_options, kinc_framebuffer_options_t *framebuffer_options);
|
||||
void (*window_destroy)(int window_index);
|
||||
int (*window_display)(int window_index);
|
||||
void (*window_show)(int window_index);
|
||||
void (*window_hide)(int window_index);
|
||||
void (*window_set_title)(int window_index, const char *title);
|
||||
void (*window_change_mode)(int window_index, kinc_window_mode_t mode);
|
||||
kinc_window_mode_t (*window_get_mode)(int window_index);
|
||||
void (*window_move)(int window_index, int x, int y);
|
||||
void (*window_resize)(int window_index, int width, int height);
|
||||
int (*window_x)(int window_index);
|
||||
int (*window_y)(int window_index);
|
||||
int (*window_width)(int window_index);
|
||||
int (*window_height)(int window_index);
|
||||
int (*count_windows)(void);
|
||||
|
||||
bool (*mouse_can_lock)(void);
|
||||
bool (*mouse_is_locked)(void);
|
||||
void (*mouse_lock)(int window);
|
||||
void (*mouse_unlock)(void);
|
||||
void (*mouse_show)(void);
|
||||
void (*mouse_hide)(void);
|
||||
void (*mouse_set_position)(int window, int x, int y);
|
||||
void (*mouse_get_position)(int window, int *x, int *y);
|
||||
void (*mouse_set_cursor)(int cursor);
|
||||
|
||||
void (*copy_to_clipboard)(const char *text);
|
||||
#ifdef KINC_EGL
|
||||
EGLDisplay (*egl_get_display)(void);
|
||||
EGLNativeWindowType (*egl_get_native_window)(EGLDisplay display, EGLConfig config, int window_index);
|
||||
#endif
|
||||
#ifdef KINC_VULKAN
|
||||
void (*vulkan_get_instance_extensions)(const char **extensions, int *count, int max);
|
||||
VkResult (*vulkan_create_surface)(VkInstance instance, int window_index, VkSurfaceKHR *surface);
|
||||
VkBool32 (*vulkan_get_physical_device_presentation_support)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct linux_procs procs;
|
||||
|
||||
void kinc_linux_init_procs();
|
198
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/gamepad.c.h
Normal file
198
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/gamepad.c.h
Normal file
@ -0,0 +1,198 @@
|
||||
#include "gamepad.h"
|
||||
|
||||
#include <kinc/input/gamepad.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libudev.h>
|
||||
#include <linux/joystick.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct HIDGamepad {
|
||||
int idx;
|
||||
char gamepad_dev_name[256];
|
||||
char name[385];
|
||||
int file_descriptor;
|
||||
bool connected;
|
||||
struct js_event gamepadEvent;
|
||||
};
|
||||
|
||||
static void HIDGamepad_open(struct HIDGamepad *pad) {
|
||||
pad->file_descriptor = open(pad->gamepad_dev_name, O_RDONLY | O_NONBLOCK);
|
||||
if (pad->file_descriptor < 0) {
|
||||
pad->connected = false;
|
||||
}
|
||||
else {
|
||||
pad->connected = true;
|
||||
|
||||
char buf[128];
|
||||
if (ioctl(pad->file_descriptor, JSIOCGNAME(sizeof(buf)), buf) < 0) {
|
||||
strncpy(buf, "Unknown", sizeof(buf));
|
||||
}
|
||||
snprintf(pad->name, sizeof(pad->name), "%s(%s)", buf, pad->gamepad_dev_name);
|
||||
kinc_internal_gamepad_trigger_connect(pad->idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDGamepad_init(struct HIDGamepad *pad, int index) {
|
||||
pad->file_descriptor = -1;
|
||||
pad->connected = false;
|
||||
pad->gamepad_dev_name[0] = 0;
|
||||
if (index >= 0 && index < 12) {
|
||||
pad->idx = index;
|
||||
snprintf(pad->gamepad_dev_name, sizeof(pad->gamepad_dev_name), "/dev/input/js%d", pad->idx);
|
||||
HIDGamepad_open(pad);
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDGamepad_close(struct HIDGamepad *pad) {
|
||||
if (pad->connected) {
|
||||
kinc_internal_gamepad_trigger_disconnect(pad->idx);
|
||||
close(pad->file_descriptor);
|
||||
pad->file_descriptor = -1;
|
||||
pad->connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
void HIDGamepad_processEvent(struct HIDGamepad *pad, struct js_event e) {
|
||||
switch (e.type) {
|
||||
case JS_EVENT_BUTTON:
|
||||
kinc_internal_gamepad_trigger_button(pad->idx, e.number, e.value);
|
||||
break;
|
||||
case JS_EVENT_AXIS: {
|
||||
float value = e.number % 2 == 0 ? e.value : -e.value;
|
||||
kinc_internal_gamepad_trigger_axis(pad->idx, e.number, value / 32767.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HIDGamepad_update(struct HIDGamepad *pad) {
|
||||
if (pad->connected) {
|
||||
while (read(pad->file_descriptor, &pad->gamepadEvent, sizeof(pad->gamepadEvent)) > 0) {
|
||||
HIDGamepad_processEvent(pad, pad->gamepadEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HIDGamepadUdevHelper {
|
||||
struct udev *udevPtr;
|
||||
struct udev_monitor *udevMonitorPtr;
|
||||
int udevMonitorFD;
|
||||
};
|
||||
|
||||
static struct HIDGamepadUdevHelper udev_helper;
|
||||
|
||||
static struct HIDGamepad gamepads[KINC_GAMEPAD_MAX_COUNT];
|
||||
|
||||
static void HIDGamepadUdevHelper_openOrCloseGamepad(struct HIDGamepadUdevHelper *helper, struct udev_device *dev) {
|
||||
const char *action = udev_device_get_action(dev);
|
||||
if (!action)
|
||||
action = "add";
|
||||
|
||||
const char *joystickDevnodeName = strstr(udev_device_get_devnode(dev), "js");
|
||||
|
||||
if (joystickDevnodeName) {
|
||||
int joystickDevnodeIndex;
|
||||
sscanf(joystickDevnodeName, "js%d", &joystickDevnodeIndex);
|
||||
|
||||
if (!strcmp(action, "add")) {
|
||||
HIDGamepad_open(&gamepads[joystickDevnodeIndex]);
|
||||
}
|
||||
|
||||
if (!strcmp(action, "remove")) {
|
||||
HIDGamepad_close(&gamepads[joystickDevnodeIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDGamepadUdevHelper_processDevice(struct HIDGamepadUdevHelper *helper, struct udev_device *dev) {
|
||||
if (dev) {
|
||||
if (udev_device_get_devnode(dev))
|
||||
HIDGamepadUdevHelper_openOrCloseGamepad(helper, dev);
|
||||
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDGamepadUdevHelper_init(struct HIDGamepadUdevHelper *helper) {
|
||||
struct udev *udevPtrNew = udev_new();
|
||||
|
||||
// enumerate
|
||||
struct udev_enumerate *enumerate = udev_enumerate_new(udevPtrNew);
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerate, "input");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
|
||||
struct udev_list_entry *entry;
|
||||
|
||||
udev_list_entry_foreach(entry, devices) {
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev = udev_device_new_from_syspath(udevPtrNew, path);
|
||||
HIDGamepadUdevHelper_processDevice(helper, dev);
|
||||
}
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
// setup mon
|
||||
helper->udevMonitorPtr = udev_monitor_new_from_netlink(udevPtrNew, "udev");
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(helper->udevMonitorPtr, "input", NULL);
|
||||
udev_monitor_enable_receiving(helper->udevMonitorPtr);
|
||||
|
||||
helper->udevMonitorFD = udev_monitor_get_fd(helper->udevMonitorPtr);
|
||||
|
||||
helper->udevPtr = udevPtrNew;
|
||||
}
|
||||
|
||||
static void HIDGamepadUdevHelper_update(struct HIDGamepadUdevHelper *helper) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(helper->udevMonitorFD, &fds);
|
||||
|
||||
if (FD_ISSET(helper->udevMonitorFD, &fds)) {
|
||||
struct udev_device *dev = udev_monitor_receive_device(helper->udevMonitorPtr);
|
||||
HIDGamepadUdevHelper_processDevice(helper, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDGamepadUdevHelper_close(struct HIDGamepadUdevHelper *helper) {
|
||||
udev_unref(helper->udevPtr);
|
||||
}
|
||||
|
||||
void kinc_linux_initHIDGamepads() {
|
||||
for (int i = 0; i < KINC_GAMEPAD_MAX_COUNT; ++i) {
|
||||
HIDGamepad_init(&gamepads[i], i);
|
||||
}
|
||||
HIDGamepadUdevHelper_init(&udev_helper);
|
||||
}
|
||||
|
||||
void kinc_linux_updateHIDGamepads() {
|
||||
HIDGamepadUdevHelper_update(&udev_helper);
|
||||
for (int i = 0; i < KINC_GAMEPAD_MAX_COUNT; ++i) {
|
||||
HIDGamepad_update(&gamepads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_linux_closeHIDGamepads() {
|
||||
HIDGamepadUdevHelper_close(&udev_helper);
|
||||
}
|
||||
|
||||
const char *kinc_gamepad_vendor(int gamepad) {
|
||||
return "Linux gamepad";
|
||||
}
|
||||
|
||||
const char *kinc_gamepad_product_name(int gamepad) {
|
||||
return gamepad >= 0 && gamepad < KINC_GAMEPAD_MAX_COUNT ? gamepads[gamepad].name : "";
|
||||
}
|
||||
|
||||
bool kinc_gamepad_connected(int gamepad) {
|
||||
return gamepad >= 0 && gamepad < KINC_GAMEPAD_MAX_COUNT && gamepads[gamepad].connected;
|
||||
}
|
||||
|
||||
void kinc_gamepad_rumble(int gamepad, float left, float right) {}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void kinc_linux_initHIDGamepads();
|
||||
void kinc_linux_updateHIDGamepads();
|
||||
void kinc_linux_closeHIDGamepads();
|
161
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/linuxunit.c
Normal file
161
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/linuxunit.c
Normal file
@ -0,0 +1,161 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE // memfd_create and mkostemp
|
||||
#endif
|
||||
#include "funcs.h"
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void load_lib(void **lib, const char *name) {
|
||||
char libname[64];
|
||||
sprintf(libname, "lib%s.so", name);
|
||||
*lib = dlopen(libname, RTLD_LAZY);
|
||||
if (*lib != NULL) {
|
||||
return;
|
||||
}
|
||||
// Ubuntu and Fedora only ship libFoo.so.major by default, so look for those.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sprintf(libname, "lib%s.so.%i", name, i);
|
||||
*lib = dlopen(libname, RTLD_LAZY);
|
||||
if (*lib != NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef KINC_NO_WAYLAND
|
||||
#include "wayland/display.c.h"
|
||||
#include "wayland/system.c.h"
|
||||
#include "wayland/window.c.h"
|
||||
#endif
|
||||
|
||||
#ifndef KINC_NO_X11
|
||||
#include "x11/display.c.h"
|
||||
#include "x11/system.c.h"
|
||||
#include "x11/window.c.h"
|
||||
#endif
|
||||
|
||||
struct linux_procs procs = {0};
|
||||
|
||||
void kinc_linux_init_procs() {
|
||||
if (procs.window_create != NULL) {
|
||||
return;
|
||||
}
|
||||
#ifndef KINC_NO_WAYLAND
|
||||
if (kinc_wayland_init()) {
|
||||
procs.handle_messages = kinc_wayland_handle_messages;
|
||||
procs.shutdown = kinc_wayland_shutdown;
|
||||
|
||||
procs.window_create = kinc_wayland_window_create;
|
||||
procs.window_width = kinc_wayland_window_width;
|
||||
procs.window_height = kinc_wayland_window_height;
|
||||
procs.window_x = kinc_wayland_window_x;
|
||||
procs.window_y = kinc_wayland_window_y;
|
||||
procs.window_destroy = kinc_wayland_window_destroy;
|
||||
procs.window_change_mode = kinc_wayland_window_change_mode;
|
||||
procs.window_get_mode = kinc_wayland_window_get_mode;
|
||||
procs.window_set_title = kinc_wayland_window_set_title;
|
||||
procs.window_display = kinc_wayland_window_display;
|
||||
procs.window_move = kinc_wayland_window_move;
|
||||
procs.window_resize = kinc_wayland_window_resize;
|
||||
procs.window_show = kinc_wayland_window_show;
|
||||
procs.window_hide = kinc_wayland_window_hide;
|
||||
procs.count_windows = kinc_wayland_count_windows;
|
||||
|
||||
procs.mouse_can_lock = kinc_wl_mouse_can_lock;
|
||||
procs.mouse_lock = kinc_wl_mouse_lock;
|
||||
procs.mouse_unlock = kinc_wl_mouse_unlock;
|
||||
procs.mouse_show = kinc_wl_mouse_show;
|
||||
procs.mouse_hide = kinc_wl_mouse_hide;
|
||||
procs.mouse_set_position = kinc_wl_mouse_set_position;
|
||||
procs.mouse_get_position = kinc_wl_mouse_get_position;
|
||||
procs.mouse_set_cursor = kinc_wl_mouse_set_cursor;
|
||||
|
||||
procs.display_init = kinc_wayland_display_init;
|
||||
procs.display_available = kinc_wayland_display_available;
|
||||
procs.display_available_mode = kinc_wayland_display_available_mode;
|
||||
procs.display_count_available_modes = kinc_wayland_display_count_available_modes;
|
||||
procs.display_current_mode = kinc_wayland_display_current_mode;
|
||||
procs.display_name = kinc_wayland_display_name;
|
||||
procs.display_primary = kinc_wayland_display_primary;
|
||||
procs.count_displays = kinc_wayland_count_displays;
|
||||
|
||||
procs.copy_to_clipboard = kinc_wayland_copy_to_clipboard;
|
||||
#ifdef KINC_EGL
|
||||
procs.egl_get_display = kinc_wayland_egl_get_display;
|
||||
procs.egl_get_native_window = kinc_wayland_egl_get_native_window;
|
||||
#endif
|
||||
#ifdef KINC_VULKAN
|
||||
procs.vulkan_create_surface = kinc_wayland_vulkan_create_surface;
|
||||
procs.vulkan_get_instance_extensions = kinc_wayland_vulkan_get_instance_extensions;
|
||||
procs.vulkan_get_physical_device_presentation_support = kinc_wayland_vulkan_get_physical_device_presentation_support;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifndef KINC_NO_X11
|
||||
if (kinc_x11_init()) {
|
||||
procs.handle_messages = kinc_x11_handle_messages;
|
||||
procs.shutdown = kinc_x11_shutdown;
|
||||
|
||||
procs.window_create = kinc_x11_window_create;
|
||||
procs.window_width = kinc_x11_window_width;
|
||||
procs.window_height = kinc_x11_window_height;
|
||||
procs.window_x = kinc_x11_window_x;
|
||||
procs.window_y = kinc_x11_window_y;
|
||||
procs.window_destroy = kinc_x11_window_destroy;
|
||||
procs.window_change_mode = kinc_x11_window_change_mode;
|
||||
procs.window_get_mode = kinc_x11_window_get_mode;
|
||||
procs.window_set_title = kinc_x11_window_set_title;
|
||||
procs.window_display = kinc_x11_window_display;
|
||||
procs.window_move = kinc_x11_window_move;
|
||||
procs.window_resize = kinc_x11_window_resize;
|
||||
procs.window_show = kinc_x11_window_show;
|
||||
procs.window_hide = kinc_x11_window_hide;
|
||||
procs.count_windows = kinc_x11_count_windows;
|
||||
|
||||
procs.display_init = kinc_x11_display_init;
|
||||
procs.display_available = kinc_x11_display_available;
|
||||
procs.display_available_mode = kinc_x11_display_available_mode;
|
||||
procs.display_count_available_modes = kinc_x11_display_count_available_modes;
|
||||
procs.display_current_mode = kinc_x11_display_current_mode;
|
||||
procs.display_name = kinc_x11_display_name;
|
||||
procs.display_primary = kinc_x11_display_primary;
|
||||
procs.count_displays = kinc_x11_count_displays;
|
||||
|
||||
procs.mouse_can_lock = kinc_x11_mouse_can_lock;
|
||||
procs.mouse_lock = kinc_x11_mouse_lock;
|
||||
procs.mouse_unlock = kinc_x11_mouse_unlock;
|
||||
procs.mouse_show = kinc_x11_mouse_show;
|
||||
procs.mouse_hide = kinc_x11_mouse_hide;
|
||||
procs.mouse_set_position = kinc_x11_mouse_set_position;
|
||||
procs.mouse_get_position = kinc_x11_mouse_get_position;
|
||||
procs.mouse_set_cursor = kinc_x11_mouse_set_cursor;
|
||||
|
||||
procs.copy_to_clipboard = kinc_x11_copy_to_clipboard;
|
||||
#ifdef KINC_EGL
|
||||
procs.egl_get_display = kinc_x11_egl_get_display;
|
||||
procs.egl_get_native_window = kinc_x11_egl_get_native_window;
|
||||
#endif
|
||||
#ifdef KINC_VULKAN
|
||||
procs.vulkan_create_surface = kinc_x11_vulkan_create_surface;
|
||||
procs.vulkan_get_instance_extensions = kinc_x11_vulkan_get_instance_extensions;
|
||||
procs.vulkan_get_physical_device_presentation_support = kinc_x11_vulkan_get_physical_device_presentation_support;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Neither wayland nor X11 found.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#include "display.c.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "gamepad.c.h"
|
||||
#endif
|
||||
#include "mouse.c.h"
|
||||
#include "sound.c.h"
|
||||
#include "system.c.h"
|
||||
#include "video.c.h"
|
||||
#include "window.c.h"
|
@ -0,0 +1,36 @@
|
||||
#include "funcs.h"
|
||||
#include <kinc/input/mouse.h>
|
||||
|
||||
void kinc_internal_mouse_lock(int window) {
|
||||
procs.mouse_lock(window);
|
||||
}
|
||||
|
||||
void kinc_internal_mouse_unlock() {
|
||||
procs.mouse_unlock();
|
||||
}
|
||||
|
||||
bool kinc_mouse_can_lock(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _mouseHidden = false;
|
||||
|
||||
void kinc_mouse_show() {
|
||||
procs.mouse_show();
|
||||
}
|
||||
|
||||
void kinc_mouse_hide() {
|
||||
procs.mouse_hide();
|
||||
}
|
||||
|
||||
void kinc_mouse_set_cursor(int cursorIndex) {
|
||||
procs.mouse_set_cursor(cursorIndex);
|
||||
}
|
||||
|
||||
void kinc_mouse_set_position(int window, int x, int y) {
|
||||
procs.mouse_set_position(window, x, y);
|
||||
}
|
||||
|
||||
void kinc_mouse_get_position(int window, int *x, int *y) {
|
||||
procs.mouse_get_position(window, x, y);
|
||||
}
|
233
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/sound.c.h
Normal file
233
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/sound.c.h
Normal file
@ -0,0 +1,233 @@
|
||||
#include <kinc/audio2/audio.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// apt-get install libasound2-dev
|
||||
|
||||
kinc_a2_buffer_t a2_buffer;
|
||||
|
||||
pthread_t threadid;
|
||||
bool audioRunning = false;
|
||||
snd_pcm_t *playback_handle;
|
||||
short buf[4096 * 4];
|
||||
|
||||
static unsigned int samples_per_second = 44100;
|
||||
|
||||
uint32_t kinc_a2_samples_per_second(void) {
|
||||
return samples_per_second;
|
||||
}
|
||||
|
||||
void copySample(void *buffer) {
|
||||
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
|
||||
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
|
||||
a2_buffer.read_location += 1;
|
||||
if (a2_buffer.read_location >= a2_buffer.data_size) {
|
||||
a2_buffer.read_location = 0;
|
||||
}
|
||||
((int16_t *)buffer)[0] = (int16_t)(left_value * 32767);
|
||||
((int16_t *)buffer)[1] = (int16_t)(right_value * 32767);
|
||||
}
|
||||
|
||||
int playback_callback(snd_pcm_sframes_t nframes) {
|
||||
int err = 0;
|
||||
if (kinc_a2_internal_callback(&a2_buffer, nframes)) {
|
||||
int ni = 0;
|
||||
while (ni < nframes) {
|
||||
int i = 0;
|
||||
for (; ni < nframes && i < 4096 * 2; ++i, ++ni) {
|
||||
copySample(&buf[i * 2]);
|
||||
}
|
||||
int err2;
|
||||
if ((err2 = snd_pcm_writei(playback_handle, buf, i)) < 0) {
|
||||
fprintf(stderr, "write failed (%s)\n", snd_strerror(err2));
|
||||
}
|
||||
err += err2;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
bool tryToRecover(snd_pcm_t *handle, int errorCode) {
|
||||
switch (-errorCode) {
|
||||
case EINTR:
|
||||
case EPIPE:
|
||||
case ESPIPE:
|
||||
#if !defined(__FreeBSD__)
|
||||
case ESTRPIPE:
|
||||
#endif
|
||||
{
|
||||
int recovered = snd_pcm_recover(playback_handle, errorCode, 1);
|
||||
|
||||
if (recovered != 0) {
|
||||
fprintf(stderr, "unable to recover from ALSA error code=%i\n", errorCode);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "recovered from ALSA error code=%i\n", errorCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "unhandled ALSA error code=%i\n", errorCode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void *doAudio(void *arg) {
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
snd_pcm_sw_params_t *sw_params;
|
||||
snd_pcm_sframes_t frames_to_deliver;
|
||||
int err;
|
||||
|
||||
if ((err = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||
fprintf(stderr, "cannot open audio device default (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
|
||||
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0) {
|
||||
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||
fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
|
||||
fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dir = 0;
|
||||
if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &samples_per_second, &dir)) < 0) {
|
||||
fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)) < 0) {
|
||||
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snd_pcm_uframes_t bufferSize = samples_per_second / 8;
|
||||
if (((err = snd_pcm_hw_params_set_buffer_size(playback_handle, hw_params, bufferSize)) < 0 &&
|
||||
(snd_pcm_hw_params_set_buffer_size_near(playback_handle, hw_params, &bufferSize)) < 0)) {
|
||||
fprintf(stderr, "cannot set buffer size (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0) {
|
||||
fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
/* tell ALSA to wake us up whenever 4096 or more frames
|
||||
of playback data can be delivered. Also, tell
|
||||
ALSA that we'll start the device ourselves.
|
||||
*/
|
||||
|
||||
if ((err = snd_pcm_sw_params_malloc(&sw_params)) < 0) {
|
||||
fprintf(stderr, "cannot allocate software parameters structure (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_current(playback_handle, sw_params)) < 0) {
|
||||
fprintf(stderr, "cannot initialize software parameters structure (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_set_avail_min(playback_handle, sw_params, 4096)) < 0) {
|
||||
fprintf(stderr, "cannot set minimum available count (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_set_start_threshold(playback_handle, sw_params, 0U)) < 0) {
|
||||
fprintf(stderr, "cannot set start mode (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params(playback_handle, sw_params)) < 0) {
|
||||
fprintf(stderr, "cannot set software parameters (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the interface will interrupt the kernel every 4096 frames, and ALSA
|
||||
will wake up this program very soon after that.
|
||||
*/
|
||||
|
||||
if ((err = snd_pcm_prepare(playback_handle)) < 0) {
|
||||
fprintf(stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (audioRunning) {
|
||||
|
||||
/* wait till the interface is ready for data, or 1 second
|
||||
has elapsed.
|
||||
*/
|
||||
|
||||
if ((err = snd_pcm_wait(playback_handle, 1000)) < 0) {
|
||||
fprintf(stderr, "poll failed (%s)\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
/* find out how much space is available for playback data */
|
||||
|
||||
if ((frames_to_deliver = snd_pcm_avail_update(playback_handle)) < 0) {
|
||||
if (!tryToRecover(playback_handle, frames_to_deliver)) {
|
||||
// break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver;
|
||||
|
||||
/* deliver the data */
|
||||
|
||||
int delivered = playback_callback(frames_to_deliver);
|
||||
|
||||
if (delivered != frames_to_deliver) {
|
||||
fprintf(stderr, "playback callback failed (delivered %i / %ld frames)\n", delivered, frames_to_deliver);
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snd_pcm_close(playback_handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
void kinc_a2_init() {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
kinc_a2_internal_init();
|
||||
initialized = true;
|
||||
|
||||
a2_buffer.read_location = 0;
|
||||
a2_buffer.write_location = 0;
|
||||
a2_buffer.data_size = 128 * 1024;
|
||||
a2_buffer.channel_count = 2;
|
||||
a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
|
||||
a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));
|
||||
|
||||
audioRunning = true;
|
||||
pthread_create(&threadid, NULL, &doAudio, NULL);
|
||||
}
|
||||
|
||||
void kinc_a2_update() {}
|
||||
|
||||
void kinc_a2_shutdown() {
|
||||
audioRunning = false;
|
||||
}
|
433
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/system.c.h
Normal file
433
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/system.c.h
Normal file
@ -0,0 +1,433 @@
|
||||
#include "kinc/graphics4/graphics.h"
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/input/gamepad.h>
|
||||
#include <kinc/input/keyboard.h>
|
||||
#include <kinc/input/mouse.h>
|
||||
#include <kinc/input/pen.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/video.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#include "gamepad.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "funcs.h"
|
||||
|
||||
bool kinc_internal_handle_messages() {
|
||||
if (!procs.handle_messages()) {
|
||||
return false;
|
||||
}
|
||||
#ifndef __FreeBSD__
|
||||
kinc_linux_updateHIDGamepads();
|
||||
#endif // TODO: add #else with proper call to FreeBSD backend impl
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *kinc_system_id() {
|
||||
return "Linux";
|
||||
}
|
||||
|
||||
void kinc_set_keep_screen_on(bool on) {}
|
||||
|
||||
void kinc_keyboard_show() {}
|
||||
|
||||
void kinc_keyboard_hide() {}
|
||||
|
||||
bool kinc_keyboard_active() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void kinc_load_url(const char *url) {
|
||||
#define MAX_COMMAND_BUFFER_SIZE 256
|
||||
#define HTTP "http://"
|
||||
#define HTTPS "https://"
|
||||
if (strncmp(url, HTTP, sizeof(HTTP) - 1) == 0 || strncmp(url, HTTPS, sizeof(HTTPS) - 1) == 0) {
|
||||
char openUrlCommand[MAX_COMMAND_BUFFER_SIZE];
|
||||
snprintf(openUrlCommand, MAX_COMMAND_BUFFER_SIZE, "xdg-open %s", url);
|
||||
int err = system(openUrlCommand);
|
||||
if (err != 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Error opening url %s", url);
|
||||
}
|
||||
}
|
||||
#undef HTTPS
|
||||
#undef HTTP
|
||||
#undef MAX_COMMAND_BUFFER_SIZE
|
||||
}
|
||||
|
||||
void kinc_vibrate(int ms) {}
|
||||
|
||||
const char *kinc_language() {
|
||||
return "en";
|
||||
}
|
||||
|
||||
static char save[2000];
|
||||
static bool saveInitialized = false;
|
||||
|
||||
const char *kinc_internal_save_path() {
|
||||
// first check for an existing directory in $HOME
|
||||
// if one exists, use it, else create one in $XDG_DATA_HOME
|
||||
// See: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
if (!saveInitialized) {
|
||||
const char *homedir;
|
||||
|
||||
if ((homedir = getenv("HOME")) == NULL) {
|
||||
homedir = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
|
||||
strcpy(save, homedir);
|
||||
strcat(save, "/.");
|
||||
strcat(save, kinc_application_name());
|
||||
strcat(save, "/");
|
||||
struct stat st;
|
||||
if (stat(save, &st) == 0) {
|
||||
// use existing folder in $HOME
|
||||
}
|
||||
else {
|
||||
// use XDG folder
|
||||
const char *data_home;
|
||||
if ((data_home = getenv("XDG_DATA_HOME")) == NULL) {
|
||||
// $XDG_DATA_HOME is not defined, fall back to the default, $HOME/.local/share
|
||||
strcpy(save, homedir);
|
||||
strcat(save, "/.local/share/");
|
||||
}
|
||||
else {
|
||||
// use $XDG_DATA_HOME
|
||||
strcpy(save, data_home);
|
||||
if (data_home[strlen(data_home) - 1] != '/') {
|
||||
strcat(save, "/");
|
||||
}
|
||||
}
|
||||
strcat(save, kinc_application_name());
|
||||
strcat(save, "/");
|
||||
int res = mkdir(save, 0700);
|
||||
if (res != 0 && errno != EEXIST) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not create save directory '%s'. Error %d", save, errno);
|
||||
}
|
||||
}
|
||||
|
||||
saveInitialized = true;
|
||||
}
|
||||
return save;
|
||||
}
|
||||
|
||||
static const char *videoFormats[] = {"ogv", NULL};
|
||||
|
||||
const char **kinc_video_formats() {
|
||||
return videoFormats;
|
||||
}
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
double kinc_frequency(void) {
|
||||
return 1000000.0;
|
||||
}
|
||||
|
||||
static struct timeval start;
|
||||
|
||||
kinc_ticks_t kinc_timestamp(void) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
now.tv_sec -= start.tv_sec;
|
||||
now.tv_usec -= start.tv_usec;
|
||||
return (kinc_ticks_t)now.tv_sec * 1000000 + (kinc_ticks_t)now.tv_usec;
|
||||
}
|
||||
|
||||
void kinc_login() {}
|
||||
|
||||
void kinc_unlock_achievement(int id) {}
|
||||
|
||||
void kinc_linux_init_procs();
|
||||
|
||||
#ifdef KINC_KONG
|
||||
void kong_init(void);
|
||||
#endif
|
||||
|
||||
int kinc_init(const char *name, int width, int height, kinc_window_options_t *win, kinc_framebuffer_options_t *frame) {
|
||||
#ifndef __FreeBSD__
|
||||
kinc_linux_initHIDGamepads();
|
||||
#endif // TODO: add #else with proper call to FreeBSD backend impl
|
||||
|
||||
gettimeofday(&start, NULL);
|
||||
kinc_linux_init_procs();
|
||||
kinc_display_init();
|
||||
|
||||
kinc_set_application_name(name);
|
||||
|
||||
kinc_g4_internal_init();
|
||||
|
||||
kinc_window_options_t defaultWin;
|
||||
if (win == NULL) {
|
||||
kinc_window_options_set_defaults(&defaultWin);
|
||||
win = &defaultWin;
|
||||
}
|
||||
kinc_framebuffer_options_t defaultFrame;
|
||||
if (frame == NULL) {
|
||||
kinc_framebuffer_options_set_defaults(&defaultFrame);
|
||||
frame = &defaultFrame;
|
||||
}
|
||||
win->width = width;
|
||||
win->height = height;
|
||||
if (win->title == NULL) {
|
||||
win->title = name;
|
||||
}
|
||||
|
||||
int window = kinc_window_create(win, frame);
|
||||
#ifdef KINC_KONG
|
||||
kong_init();
|
||||
#endif
|
||||
return window;
|
||||
}
|
||||
|
||||
void kinc_internal_shutdown() {
|
||||
kinc_g4_internal_destroy();
|
||||
#ifndef __FreeBSD__
|
||||
kinc_linux_closeHIDGamepads();
|
||||
#endif // TODO: add #else with proper call to FreeBSD backend impl
|
||||
procs.shutdown();
|
||||
kinc_internal_shutdown_callback();
|
||||
}
|
||||
|
||||
#ifndef KINC_NO_MAIN
|
||||
int main(int argc, char **argv) {
|
||||
return kickstart(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
void kinc_copy_to_clipboard(const char *text) {
|
||||
procs.copy_to_clipboard(text);
|
||||
}
|
||||
|
||||
static int parse_number_at_end_of_line(char *line) {
|
||||
char *end = &line[strlen(line) - 2];
|
||||
int num = 0;
|
||||
int multi = 1;
|
||||
while (*end >= '0' && *end <= '9') {
|
||||
num += (*end - '0') * multi;
|
||||
multi *= 10;
|
||||
--end;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int kinc_cpu_cores(void) {
|
||||
char line[1024];
|
||||
FILE *file = fopen("/proc/cpuinfo", "r");
|
||||
|
||||
if (file != NULL) {
|
||||
int cores[1024];
|
||||
memset(cores, 0, sizeof(cores));
|
||||
|
||||
int cpu_count = 0;
|
||||
int physical_id = -1;
|
||||
int per_cpu_cores = -1;
|
||||
int processor_count = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
if (strncmp(line, "processor", 9) == 0) {
|
||||
++processor_count;
|
||||
if (physical_id >= 0 && per_cpu_cores > 0) {
|
||||
if (physical_id + 1 > cpu_count) {
|
||||
cpu_count = physical_id + 1;
|
||||
}
|
||||
cores[physical_id] = per_cpu_cores;
|
||||
physical_id = -1;
|
||||
per_cpu_cores = -1;
|
||||
}
|
||||
}
|
||||
else if (strncmp(line, "physical id", 11) == 0) {
|
||||
physical_id = parse_number_at_end_of_line(line);
|
||||
}
|
||||
else if (strncmp(line, "cpu cores", 9) == 0) {
|
||||
per_cpu_cores = parse_number_at_end_of_line(line);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
if (physical_id >= 0 && per_cpu_cores > 0) {
|
||||
if (physical_id + 1 > cpu_count) {
|
||||
cpu_count = physical_id + 1;
|
||||
}
|
||||
cores[physical_id] = per_cpu_cores;
|
||||
}
|
||||
|
||||
int proper_cpu_count = 0;
|
||||
for (int i = 0; i < cpu_count; ++i) {
|
||||
proper_cpu_count += cores[i];
|
||||
}
|
||||
|
||||
if (proper_cpu_count > 0) {
|
||||
return proper_cpu_count;
|
||||
}
|
||||
else {
|
||||
return processor_count == 0 ? 1 : processor_count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
};
|
||||
}
|
||||
|
||||
int kinc_hardware_threads(void) {
|
||||
#ifndef __FreeBSD__
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
return kinc_cpu_cores();
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
int xkb_to_kinc(xkb_keysym_t symbol) {
|
||||
#define KEY(xkb, kinc) \
|
||||
case xkb: \
|
||||
return kinc;
|
||||
switch (symbol) {
|
||||
KEY(XKB_KEY_Right, KINC_KEY_RIGHT)
|
||||
KEY(XKB_KEY_Left, KINC_KEY_LEFT)
|
||||
KEY(XKB_KEY_Up, KINC_KEY_UP)
|
||||
KEY(XKB_KEY_Down, KINC_KEY_DOWN)
|
||||
KEY(XKB_KEY_space, KINC_KEY_SPACE)
|
||||
KEY(XKB_KEY_BackSpace, KINC_KEY_BACKSPACE)
|
||||
KEY(XKB_KEY_Tab, KINC_KEY_TAB)
|
||||
KEY(XKB_KEY_Return, KINC_KEY_RETURN)
|
||||
KEY(XKB_KEY_Shift_L, KINC_KEY_SHIFT)
|
||||
KEY(XKB_KEY_Shift_R, KINC_KEY_SHIFT)
|
||||
KEY(XKB_KEY_Control_L, KINC_KEY_CONTROL)
|
||||
KEY(XKB_KEY_Control_R, KINC_KEY_CONTROL)
|
||||
KEY(XKB_KEY_Alt_L, KINC_KEY_ALT)
|
||||
KEY(XKB_KEY_Alt_R, KINC_KEY_ALT)
|
||||
KEY(XKB_KEY_Delete, KINC_KEY_DELETE)
|
||||
KEY(XKB_KEY_comma, KINC_KEY_COMMA)
|
||||
KEY(XKB_KEY_period, KINC_KEY_PERIOD)
|
||||
KEY(XKB_KEY_bracketleft, KINC_KEY_OPEN_BRACKET)
|
||||
KEY(XKB_KEY_bracketright, KINC_KEY_CLOSE_BRACKET)
|
||||
KEY(XKB_KEY_braceleft, KINC_KEY_OPEN_CURLY_BRACKET)
|
||||
KEY(XKB_KEY_braceright, KINC_KEY_CLOSE_CURLY_BRACKET)
|
||||
KEY(XKB_KEY_parenleft, KINC_KEY_OPEN_PAREN)
|
||||
KEY(XKB_KEY_parenright, KINC_KEY_CLOSE_PAREN)
|
||||
KEY(XKB_KEY_backslash, KINC_KEY_BACK_SLASH)
|
||||
KEY(XKB_KEY_apostrophe, KINC_KEY_QUOTE)
|
||||
KEY(XKB_KEY_colon, KINC_KEY_COLON)
|
||||
KEY(XKB_KEY_semicolon, KINC_KEY_SEMICOLON)
|
||||
KEY(XKB_KEY_minus, KINC_KEY_HYPHEN_MINUS)
|
||||
KEY(XKB_KEY_underscore, KINC_KEY_UNDERSCORE)
|
||||
KEY(XKB_KEY_slash, KINC_KEY_SLASH)
|
||||
KEY(XKB_KEY_bar, KINC_KEY_PIPE)
|
||||
KEY(XKB_KEY_question, KINC_KEY_QUESTIONMARK)
|
||||
KEY(XKB_KEY_less, KINC_KEY_LESS_THAN)
|
||||
KEY(XKB_KEY_greater, KINC_KEY_GREATER_THAN)
|
||||
KEY(XKB_KEY_asterisk, KINC_KEY_ASTERISK)
|
||||
KEY(XKB_KEY_ampersand, KINC_KEY_AMPERSAND)
|
||||
KEY(XKB_KEY_asciicircum, KINC_KEY_CIRCUMFLEX)
|
||||
KEY(XKB_KEY_percent, KINC_KEY_PERCENT)
|
||||
KEY(XKB_KEY_dollar, KINC_KEY_DOLLAR)
|
||||
KEY(XKB_KEY_numbersign, KINC_KEY_HASH)
|
||||
KEY(XKB_KEY_at, KINC_KEY_AT)
|
||||
KEY(XKB_KEY_exclam, KINC_KEY_EXCLAMATION)
|
||||
KEY(XKB_KEY_equal, KINC_KEY_EQUALS)
|
||||
KEY(XKB_KEY_plus, KINC_KEY_ADD)
|
||||
KEY(XKB_KEY_quoteleft, KINC_KEY_BACK_QUOTE)
|
||||
KEY(XKB_KEY_quotedbl, KINC_KEY_DOUBLE_QUOTE)
|
||||
KEY(XKB_KEY_asciitilde, KINC_KEY_TILDE)
|
||||
KEY(XKB_KEY_Pause, KINC_KEY_PAUSE)
|
||||
KEY(XKB_KEY_Scroll_Lock, KINC_KEY_SCROLL_LOCK)
|
||||
KEY(XKB_KEY_Home, KINC_KEY_HOME)
|
||||
KEY(XKB_KEY_Page_Up, KINC_KEY_PAGE_UP)
|
||||
KEY(XKB_KEY_Page_Down, KINC_KEY_PAGE_DOWN)
|
||||
KEY(XKB_KEY_End, KINC_KEY_END)
|
||||
KEY(XKB_KEY_Insert, KINC_KEY_INSERT)
|
||||
KEY(XKB_KEY_KP_Enter, KINC_KEY_RETURN)
|
||||
KEY(XKB_KEY_KP_Multiply, KINC_KEY_MULTIPLY)
|
||||
KEY(XKB_KEY_KP_Add, KINC_KEY_ADD)
|
||||
KEY(XKB_KEY_KP_Subtract, KINC_KEY_SUBTRACT)
|
||||
KEY(XKB_KEY_KP_Decimal, KINC_KEY_DECIMAL)
|
||||
KEY(XKB_KEY_KP_Divide, KINC_KEY_DIVIDE)
|
||||
KEY(XKB_KEY_KP_0, KINC_KEY_NUMPAD_0)
|
||||
KEY(XKB_KEY_KP_1, KINC_KEY_NUMPAD_1)
|
||||
KEY(XKB_KEY_KP_2, KINC_KEY_NUMPAD_2)
|
||||
KEY(XKB_KEY_KP_3, KINC_KEY_NUMPAD_3)
|
||||
KEY(XKB_KEY_KP_4, KINC_KEY_NUMPAD_4)
|
||||
KEY(XKB_KEY_KP_5, KINC_KEY_NUMPAD_5)
|
||||
KEY(XKB_KEY_KP_6, KINC_KEY_NUMPAD_6)
|
||||
KEY(XKB_KEY_KP_7, KINC_KEY_NUMPAD_7)
|
||||
KEY(XKB_KEY_KP_8, KINC_KEY_NUMPAD_8)
|
||||
KEY(XKB_KEY_KP_9, KINC_KEY_NUMPAD_9)
|
||||
KEY(XKB_KEY_KP_Insert, KINC_KEY_INSERT)
|
||||
KEY(XKB_KEY_KP_Delete, KINC_KEY_DELETE)
|
||||
KEY(XKB_KEY_KP_End, KINC_KEY_END)
|
||||
KEY(XKB_KEY_KP_Home, KINC_KEY_HOME)
|
||||
KEY(XKB_KEY_KP_Left, KINC_KEY_LEFT)
|
||||
KEY(XKB_KEY_KP_Up, KINC_KEY_UP)
|
||||
KEY(XKB_KEY_KP_Right, KINC_KEY_RIGHT)
|
||||
KEY(XKB_KEY_KP_Down, KINC_KEY_DOWN)
|
||||
KEY(XKB_KEY_KP_Page_Up, KINC_KEY_PAGE_UP)
|
||||
KEY(XKB_KEY_KP_Page_Down, KINC_KEY_PAGE_DOWN)
|
||||
KEY(XKB_KEY_Menu, KINC_KEY_CONTEXT_MENU)
|
||||
KEY(XKB_KEY_a, KINC_KEY_A)
|
||||
KEY(XKB_KEY_b, KINC_KEY_B)
|
||||
KEY(XKB_KEY_c, KINC_KEY_C)
|
||||
KEY(XKB_KEY_d, KINC_KEY_D)
|
||||
KEY(XKB_KEY_e, KINC_KEY_E)
|
||||
KEY(XKB_KEY_f, KINC_KEY_F)
|
||||
KEY(XKB_KEY_g, KINC_KEY_G)
|
||||
KEY(XKB_KEY_h, KINC_KEY_H)
|
||||
KEY(XKB_KEY_i, KINC_KEY_I)
|
||||
KEY(XKB_KEY_j, KINC_KEY_J)
|
||||
KEY(XKB_KEY_k, KINC_KEY_K)
|
||||
KEY(XKB_KEY_l, KINC_KEY_L)
|
||||
KEY(XKB_KEY_m, KINC_KEY_M)
|
||||
KEY(XKB_KEY_n, KINC_KEY_N)
|
||||
KEY(XKB_KEY_o, KINC_KEY_O)
|
||||
KEY(XKB_KEY_p, KINC_KEY_P)
|
||||
KEY(XKB_KEY_q, KINC_KEY_Q)
|
||||
KEY(XKB_KEY_r, KINC_KEY_R)
|
||||
KEY(XKB_KEY_s, KINC_KEY_S)
|
||||
KEY(XKB_KEY_t, KINC_KEY_T)
|
||||
KEY(XKB_KEY_u, KINC_KEY_U)
|
||||
KEY(XKB_KEY_v, KINC_KEY_V)
|
||||
KEY(XKB_KEY_w, KINC_KEY_W)
|
||||
KEY(XKB_KEY_x, KINC_KEY_X)
|
||||
KEY(XKB_KEY_y, KINC_KEY_Y)
|
||||
KEY(XKB_KEY_z, KINC_KEY_Z)
|
||||
KEY(XKB_KEY_1, KINC_KEY_1)
|
||||
KEY(XKB_KEY_2, KINC_KEY_2)
|
||||
KEY(XKB_KEY_3, KINC_KEY_3)
|
||||
KEY(XKB_KEY_4, KINC_KEY_4)
|
||||
KEY(XKB_KEY_5, KINC_KEY_5)
|
||||
KEY(XKB_KEY_6, KINC_KEY_6)
|
||||
KEY(XKB_KEY_7, KINC_KEY_7)
|
||||
KEY(XKB_KEY_8, KINC_KEY_8)
|
||||
KEY(XKB_KEY_9, KINC_KEY_9)
|
||||
KEY(XKB_KEY_0, KINC_KEY_0)
|
||||
KEY(XKB_KEY_Escape, KINC_KEY_ESCAPE)
|
||||
KEY(XKB_KEY_F1, KINC_KEY_F1)
|
||||
KEY(XKB_KEY_F2, KINC_KEY_F2)
|
||||
KEY(XKB_KEY_F3, KINC_KEY_F3)
|
||||
KEY(XKB_KEY_F4, KINC_KEY_F4)
|
||||
KEY(XKB_KEY_F5, KINC_KEY_F5)
|
||||
KEY(XKB_KEY_F6, KINC_KEY_F6)
|
||||
KEY(XKB_KEY_F7, KINC_KEY_F7)
|
||||
KEY(XKB_KEY_F8, KINC_KEY_F8)
|
||||
KEY(XKB_KEY_F9, KINC_KEY_F9)
|
||||
KEY(XKB_KEY_F10, KINC_KEY_F10)
|
||||
KEY(XKB_KEY_F11, KINC_KEY_F11)
|
||||
KEY(XKB_KEY_F12, KINC_KEY_F12)
|
||||
default:
|
||||
return KINC_KEY_UNKNOWN;
|
||||
}
|
||||
#undef KEY
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
#include <kinc/video.h>
|
||||
|
||||
#if !defined(KINC_VIDEO_GSTREAMER)
|
||||
void kinc_video_init(kinc_video_t *video, const char *filename) {}
|
||||
|
||||
void kinc_video_destroy(kinc_video_t *video) {}
|
||||
|
||||
void kinc_video_play(kinc_video_t *video, bool loop) {}
|
||||
|
||||
void kinc_video_pause(kinc_video_t *video) {}
|
||||
|
||||
void kinc_video_stop(kinc_video_t *video) {}
|
||||
|
||||
int kinc_video_width(kinc_video_t *video) {
|
||||
return 256;
|
||||
}
|
||||
|
||||
int kinc_video_height(kinc_video_t *video) {
|
||||
return 256;
|
||||
}
|
||||
|
||||
kinc_g4_texture_t *kinc_video_current_image(kinc_video_t *video) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double kinc_video_duration(kinc_video_t *video) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double kinc_video_position(kinc_video_t *video) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool kinc_video_finished(kinc_video_t *video) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kinc_video_paused(kinc_video_t *video) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_video_update(kinc_video_t *video, double time) {}
|
||||
|
||||
void kinc_internal_video_sound_stream_init(kinc_internal_video_sound_stream_t *stream, int channel_count, int frequency) {}
|
||||
|
||||
void kinc_internal_video_sound_stream_destroy(kinc_internal_video_sound_stream_t *stream) {}
|
||||
|
||||
void kinc_internal_video_sound_stream_insert_data(kinc_internal_video_sound_stream_t *stream, float *data, int sample_count) {}
|
||||
|
||||
static float samples[2] = {0};
|
||||
|
||||
float *kinc_internal_video_sound_stream_next_frame(kinc_internal_video_sound_stream_t *stream) {
|
||||
return samples;
|
||||
}
|
||||
|
||||
bool kinc_internal_video_sound_stream_ended(kinc_internal_video_sound_stream_t *stream) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
31
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/video.h
Normal file
31
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/video.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(KINC_VIDEO_GSTREAMER)
|
||||
#include <kinc/backend/video_gstreamer.h>
|
||||
#else
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} kinc_video_impl_t;
|
||||
|
||||
typedef struct kinc_internal_video_sound_stream {
|
||||
int nothing;
|
||||
} kinc_internal_video_sound_stream_t;
|
||||
|
||||
void kinc_internal_video_sound_stream_init(kinc_internal_video_sound_stream_t *stream, int channel_count, int frequency);
|
||||
|
||||
void kinc_internal_video_sound_stream_destroy(kinc_internal_video_sound_stream_t *stream);
|
||||
|
||||
void kinc_internal_video_sound_stream_insert_data(kinc_internal_video_sound_stream_t *stream, float *data, int sample_count);
|
||||
|
||||
float *kinc_internal_video_sound_stream_next_frame(kinc_internal_video_sound_stream_t *stream);
|
||||
|
||||
bool kinc_internal_video_sound_stream_ended(kinc_internal_video_sound_stream_t *stream);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,52 @@
|
||||
#include "wayland.h"
|
||||
|
||||
void kinc_wayland_display_init(void) {
|
||||
// This is a no-op because displays are already registered in kinc_wayland_init,
|
||||
// which should be called before this function is ever invoked
|
||||
}
|
||||
|
||||
int kinc_wayland_display_primary(void) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
int kinc_wayland_count_displays(void) {
|
||||
return wl_ctx.num_displays;
|
||||
}
|
||||
|
||||
bool kinc_wayland_display_available(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS) {
|
||||
return false;
|
||||
}
|
||||
struct kinc_wl_display *display = &wl_ctx.displays[display_index];
|
||||
return display->output != NULL;
|
||||
}
|
||||
|
||||
const char *kinc_wayland_display_name(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_wl_display *display = &wl_ctx.displays[display_index];
|
||||
return display->name;
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_wayland_display_current_mode(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_wl_display *display = &wl_ctx.displays[display_index];
|
||||
return display->modes[display->current_mode];
|
||||
}
|
||||
|
||||
int kinc_wayland_display_count_available_modes(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_wl_display *display = &wl_ctx.displays[display_index];
|
||||
return display->num_modes;
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_wayland_display_available_mode(int display_index, int mode_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_wl_display *display = &wl_ctx.displays[display_index];
|
||||
if (mode_index >= display->num_modes)
|
||||
mode_index = 0;
|
||||
return display->modes[mode_index];
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,54 @@
|
||||
#ifndef KINC_WL_FN
|
||||
#define KINC_WL_FN(ret, name, args)
|
||||
#endif
|
||||
|
||||
KINC_WL_FUN(void, wl_event_queue_destroy, (struct wl_event_queue * queue))
|
||||
#if KINC_WL_CHECK_VERSION(1, 20, 0)
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_flags,
|
||||
(struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, ...))
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_array_flags,
|
||||
(struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args))
|
||||
#endif
|
||||
KINC_WL_FUN(void, wl_proxy_marshal, (struct wl_proxy * p, uint32_t opcode, ...))
|
||||
KINC_WL_FUN(void, wl_proxy_marshal_array, (struct wl_proxy * p, uint32_t opcode, union wl_argument *args))
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_create, (struct wl_proxy * factory, const struct wl_interface *interface))
|
||||
KINC_WL_FUN(void *, wl_proxy_create_wrapper, (void *proxy))
|
||||
KINC_WL_FUN(void, wl_proxy_wrapper_destroy, (void *proxy_wrapper))
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, ...))
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_constructor_versioned,
|
||||
(struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...))
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_array_constructor,
|
||||
(struct wl_proxy * proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface))
|
||||
KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_array_constructor_versioned,
|
||||
(struct wl_proxy * proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface, uint32_t version))
|
||||
KINC_WL_FUN(void, wl_proxy_destroy, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(int, wl_proxy_add_listener, (struct wl_proxy * proxy, void (**implementation)(void), void *data))
|
||||
KINC_WL_FUN(const void *, wl_proxy_get_listener, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(int, wl_proxy_add_dispatcher, (struct wl_proxy * proxy, wl_dispatcher_func_t dispatcher_func, const void *dispatcher_data, void *data))
|
||||
KINC_WL_FUN(void, wl_proxy_set_user_data, (struct wl_proxy * proxy, void *user_data))
|
||||
KINC_WL_FUN(void *, wl_proxy_get_user_data, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(uint32_t, wl_proxy_get_version, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(uint32_t, wl_proxy_get_id, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(void, wl_proxy_set_tag, (struct wl_proxy * proxy, const char *const *tag))
|
||||
KINC_WL_FUN(const char *const *, wl_proxy_get_tag, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(const char *, wl_proxy_get_class, (struct wl_proxy * proxy))
|
||||
KINC_WL_FUN(void, wl_proxy_set_queue, (struct wl_proxy * proxy, struct wl_event_queue *queue))
|
||||
KINC_WL_FUN(struct wl_display *, wl_display_connect, (const char *name))
|
||||
KINC_WL_FUN(struct wl_display *, wl_display_connect_to_fd, (int fd))
|
||||
KINC_WL_FUN(void, wl_display_disconnect, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_get_fd, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_dispatch, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_dispatch_queue, (struct wl_display * display, struct wl_event_queue *queue))
|
||||
KINC_WL_FUN(int, wl_display_dispatch_queue_pending, (struct wl_display * display, struct wl_event_queue *queue))
|
||||
KINC_WL_FUN(int, wl_display_dispatch_pending, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_get_error, (struct wl_display * display))
|
||||
KINC_WL_FUN(uint32_t, wl_display_get_protocol_error, (struct wl_display * display, const struct wl_interface **interface, uint32_t *id))
|
||||
KINC_WL_FUN(int, wl_display_flush, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_roundtrip_queue, (struct wl_display * display, struct wl_event_queue *queue))
|
||||
KINC_WL_FUN(int, wl_display_roundtrip, (struct wl_display * display))
|
||||
KINC_WL_FUN(struct wl_event_queue *, wl_display_create_queue, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_prepare_read_queue, (struct wl_display * display, struct wl_event_queue *queue))
|
||||
KINC_WL_FUN(int, wl_display_prepare_read, (struct wl_display * display))
|
||||
KINC_WL_FUN(void, wl_display_cancel_read, (struct wl_display * display))
|
||||
KINC_WL_FUN(int, wl_display_read_events, (struct wl_display * display))
|
||||
KINC_WL_FUN(void, wl_log_set_handler_client, (wl_log_func_t handler))
|
@ -0,0 +1,367 @@
|
||||
#pragma once
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE // put this here too, to make clangd happy
|
||||
#endif
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/system.h>
|
||||
|
||||
#include <wayland-client-core.h>
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
#define KINC_WL_CHECK_VERSION(x, y, z) \
|
||||
(WAYLAND_VERSION_MAJOR > x || (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \
|
||||
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z))
|
||||
|
||||
struct wl_surface;
|
||||
|
||||
struct kinc_wl_procs {
|
||||
#define KINC_WL_FUN(ret, name, args) ret(*_##name) args;
|
||||
#include "wayland-funs.h"
|
||||
#undef KINC_WL_FUN
|
||||
|
||||
struct wl_cursor_theme *(*_wl_cursor_theme_load)(const char *name, int size, struct wl_shm *shm);
|
||||
void (*_wl_cursor_theme_destroy)(struct wl_cursor_theme *theme);
|
||||
struct wl_cursor *(*_wl_cursor_theme_get_cursor)(struct wl_cursor_theme *theme, const char *name);
|
||||
struct wl_buffer *(*_wl_cursor_image_get_buffer)(struct wl_cursor_image *image);
|
||||
int (*_wl_cursor_frame)(struct wl_cursor *cursor, uint32_t time);
|
||||
int (*_wl_cursor_frame_and_duration)(struct wl_cursor *cursor, uint32_t time, uint32_t *duration);
|
||||
|
||||
#ifdef KINC_EGL
|
||||
struct wl_egl_window *(*_wl_egl_window_create)(struct wl_surface *surface, int width, int height);
|
||||
void (*_wl_egl_window_destroy)(struct wl_egl_window *egl_window);
|
||||
void (*_wl_egl_window_resize)(struct wl_egl_window *egl_window, int width, int height, int dx, int dy);
|
||||
void (*_wl_egl_window_get_attached_size)(struct wl_egl_window *egl_window, int *width, int *height);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define wl_event_queue_destroy wl._wl_event_queue_destroy
|
||||
#define wl_proxy_marshal_flags wl._wl_proxy_marshal_flags
|
||||
#define wl_proxy_marshal_array_flags wl._wl_proxy_marshal_array_flags
|
||||
#define wl_proxy_marshal wl._wl_proxy_marshal
|
||||
#define wl_proxy_marshal_array wl._wl_proxy_marshal_array
|
||||
#define wl_proxy_create wl._wl_proxy_create
|
||||
#define wl_proxy_create_wrapper wl._wl_proxy_create_wrapper
|
||||
#define wl_proxy_wrapper_destroy wl._wl_proxy_wrapper_destroy
|
||||
#define wl_proxy_marshal_constructor wl._wl_proxy_marshal_constructor
|
||||
#define wl_proxy_marshal_constructor_versioned wl._wl_proxy_marshal_constructor_versioned
|
||||
#define wl_proxy_marshal_array_constructor wl._wl_proxy_marshal_array_constructor
|
||||
#define wl_proxy_marshal_array_constructor_versioned wl._wl_proxy_marshal_array_constructor_versioned
|
||||
#define wl_proxy_destroy wl._wl_proxy_destroy
|
||||
#define wl_proxy_add_listener wl._wl_proxy_add_listener
|
||||
#define wl_proxy_get_listener wl._wl_proxy_get_listener
|
||||
#define wl_proxy_add_dispatcher wl._wl_proxy_add_dispatcher
|
||||
#define wl_proxy_set_user_data wl._wl_proxy_set_user_data
|
||||
#define wl_proxy_get_user_data wl._wl_proxy_get_user_data
|
||||
#define wl_proxy_get_version wl._wl_proxy_get_version
|
||||
#define wl_proxy_get_id wl._wl_proxy_get_id
|
||||
#define wl_proxy_set_tag wl._wl_proxy_set_tag
|
||||
#define wl_proxy_get_tag wl._wl_proxy_get_tag
|
||||
#define wl_proxy_get_class wl._wl_proxy_get_class
|
||||
#define wl_proxy_set_queue wl._wl_proxy_set_queue
|
||||
#define wl_display_connect wl._wl_display_connect
|
||||
#define wl_display_connect_to_fd wl._wl_display_connect_to_fd
|
||||
#define wl_display_disconnect wl._wl_display_disconnect
|
||||
#define wl_display_get_fd wl._wl_display_get_fd
|
||||
#define wl_display_dispatch wl._wl_display_dispatch
|
||||
#define wl_display_dispatch_queue wl._wl_display_dispatch_queue
|
||||
#define wl_display_dispatch_queue_pending wl._wl_display_dispatch_queue_pending
|
||||
#define wl_display_dispatch_pending wl._wl_display_dispatch_pending
|
||||
#define wl_display_get_error wl._wl_display_get_error
|
||||
#define wl_display_get_protocol_error wl._wl_display_get_protocol_error
|
||||
#define wl_display_flush wl._wl_display_flush
|
||||
#define wl_display_roundtrip_queue wl._wl_display_roundtrip_queue
|
||||
#define wl_display_roundtrip wl._wl_display_roundtrip
|
||||
#define wl_display_create_queue wl._wl_display_create_queue
|
||||
#define wl_display_prepare_read_queue wl._wl_display_prepare_read_queue
|
||||
#define wl_display_prepare_read wl._wl_display_prepare_read
|
||||
#define wl_display_cancel_read wl._wl_display_cancel_read
|
||||
#define wl_display_read_events wl._wl_display_read_events
|
||||
#define wl_log_set_handler_client wl._wl_log_set_handler_client
|
||||
|
||||
#define wl_cursor_theme_load wl._wl_cursor_theme_load
|
||||
#define wl_cursor_theme_destroy wl._wl_cursor_theme_destroy
|
||||
#define wl_cursor_theme_get_cursor wl._wl_cursor_theme_get_cursor
|
||||
#define wl_cursor_image_get_buffer wl._wl_cursor_image_get_buffer
|
||||
#define wl_cursor_frame wl._wl_cursor_frame
|
||||
#define wl_cursor_frame_and_duration wl._wl_cursor_frame_and_duration
|
||||
|
||||
#define wl_egl_window_create wl._wl_egl_window_create
|
||||
#define wl_egl_window_destroy wl._wl_egl_window_destroy
|
||||
#define wl_egl_window_resize wl._wl_egl_window_resize
|
||||
|
||||
extern struct kinc_wl_procs wl;
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-generated/wayland-pointer-constraint.h>
|
||||
#include <wayland-generated/wayland-relative-pointer.h>
|
||||
#include <wayland-generated/wayland-tablet.h>
|
||||
#include <wayland-generated/wayland-viewporter.h>
|
||||
#include <wayland-generated/xdg-decoration.h>
|
||||
#include <wayland-generated/xdg-shell.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
struct kinc_xkb_procs {
|
||||
struct xkb_context *(*xkb_context_new)(enum xkb_context_flags flags);
|
||||
void (*xkb_context_unref)(struct xkb_context *context);
|
||||
struct xkb_keymap *(*xkb_keymap_new_from_string)(struct xkb_context *context, const char *string, enum xkb_keymap_format format,
|
||||
enum xkb_keymap_compile_flags flags);
|
||||
struct xkb_state *(*xkb_state_new)(struct xkb_keymap *keymap);
|
||||
xkb_keysym_t (*xkb_state_key_get_one_sym)(struct xkb_state *state, xkb_keycode_t key);
|
||||
uint32_t (*xkb_state_key_get_utf32)(struct xkb_state *state, xkb_keycode_t key);
|
||||
xkb_mod_mask_t (*xkb_state_serialize_mods)(struct xkb_state *state, enum xkb_state_component components);
|
||||
enum xkb_state_component (*xkb_state_update_mask)(struct xkb_state *state, xkb_mod_mask_t depressed_mods, xkb_mod_mask_t latched_mods,
|
||||
xkb_mod_mask_t locked_mods, xkb_layout_index_t depressed_layout, xkb_layout_index_t latched_layout,
|
||||
xkb_layout_index_t locked_layout);
|
||||
int (*xkb_state_mod_name_is_active)(struct xkb_state *state, const char *name, enum xkb_state_component type);
|
||||
int (*xkb_keymap_key_repeats)(struct xkb_keymap *keymap, xkb_keycode_t key);
|
||||
};
|
||||
|
||||
extern struct kinc_xkb_procs wl_xkb;
|
||||
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/global.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#define MAXIMUM_WINDOWS 16
|
||||
#define MAXIMUM_DISPLAYS 16
|
||||
#define MAXIMUM_DISPLAY_MODES 16
|
||||
|
||||
struct kinc_wl_decoration {
|
||||
struct wl_surface *surface;
|
||||
struct wl_subsurface *subsurface;
|
||||
struct wp_viewport *viewport;
|
||||
};
|
||||
|
||||
enum kinc_wl_decoration_focus {
|
||||
KINC_WL_DECORATION_FOCUS_MAIN,
|
||||
KINC_WL_DECORATION_FOCUS_TOP,
|
||||
KINC_WL_DECORATION_FOCUS_LEFT,
|
||||
KINC_WL_DECORATION_FOCUS_RIGHT,
|
||||
KINC_WL_DECORATION_FOCUS_BOTTOM,
|
||||
KINC_WL_DECORATION_FOCUS_CLOSE_BUTTON,
|
||||
KINC_WL_DECORATION_FOCUS_MAX_BUTTON,
|
||||
KINC_WL_DECORATION_FOCUS_MIN_BUTTON
|
||||
};
|
||||
|
||||
#define KINC_WL_DECORATION_WIDTH 10
|
||||
|
||||
#define KINC_WL_DECORATION_TOP_X 0
|
||||
#define KINC_WL_DECORATION_TOP_Y -(KINC_WL_DECORATION_TOP_HEIGHT)
|
||||
#define KINC_WL_DECORATION_TOP_WIDTH window->width
|
||||
#define KINC_WL_DECORATION_TOP_HEIGHT KINC_WL_DECORATION_WIDTH * 3
|
||||
|
||||
#define KINC_WL_DECORATION_LEFT_X -10
|
||||
#define KINC_WL_DECORATION_LEFT_Y -(KINC_WL_DECORATION_TOP_HEIGHT)
|
||||
#define KINC_WL_DECORATION_LEFT_WIDTH KINC_WL_DECORATION_WIDTH
|
||||
#define KINC_WL_DECORATION_LEFT_HEIGHT window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT
|
||||
|
||||
#define KINC_WL_DECORATION_RIGHT_X window->width
|
||||
#define KINC_WL_DECORATION_RIGHT_Y -(KINC_WL_DECORATION_TOP_HEIGHT)
|
||||
#define KINC_WL_DECORATION_RIGHT_WIDTH 10
|
||||
#define KINC_WL_DECORATION_RIGHT_HEIGHT window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT
|
||||
|
||||
#define KINC_WL_DECORATION_BOTTOM_X 0
|
||||
#define KINC_WL_DECORATION_BOTTOM_Y window->height
|
||||
#define KINC_WL_DECORATION_BOTTOM_WIDTH window->width
|
||||
#define KINC_WL_DECORATION_BOTTOM_HEIGHT KINC_WL_DECORATION_WIDTH
|
||||
|
||||
#define KINC_WL_DECORATION_CLOSE_X window->width - 10
|
||||
#define KINC_WL_DECORATION_CLOSE_Y -20
|
||||
#define KINC_WL_DECORATION_CLOSE_WIDTH 9
|
||||
#define KINC_WL_DECORATION_CLOSE_HEIGHT 9
|
||||
|
||||
struct kinc_wl_window {
|
||||
int display_index;
|
||||
int window_id;
|
||||
int width;
|
||||
int height;
|
||||
kinc_window_mode_t mode;
|
||||
struct wl_surface *surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *toplevel;
|
||||
struct zxdg_toplevel_decoration_v1 *xdg_decoration;
|
||||
|
||||
bool configured;
|
||||
|
||||
struct {
|
||||
bool server_side;
|
||||
enum kinc_wl_decoration_focus focus;
|
||||
struct kinc_wl_decoration top;
|
||||
struct kinc_wl_decoration left;
|
||||
struct kinc_wl_decoration right;
|
||||
struct kinc_wl_decoration bottom;
|
||||
|
||||
struct kinc_wl_decoration close;
|
||||
struct kinc_wl_decoration max;
|
||||
struct kinc_wl_decoration min;
|
||||
|
||||
struct wl_buffer *dec_buffer;
|
||||
struct wl_buffer *close_buffer;
|
||||
struct wl_buffer *max_buffer;
|
||||
struct wl_buffer *min_buffer;
|
||||
} decorations;
|
||||
#ifdef KINC_EGL
|
||||
struct wl_egl_window *egl_window;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct kinc_wl_display {
|
||||
struct wl_output *output;
|
||||
int index;
|
||||
int current_mode;
|
||||
int num_modes;
|
||||
char name[64];
|
||||
int x;
|
||||
int y;
|
||||
int physical_width;
|
||||
int physical_height;
|
||||
int subpixel;
|
||||
enum wl_output_transform transform;
|
||||
enum wl_output_subpixel scale;
|
||||
kinc_display_mode_t modes[MAXIMUM_DISPLAY_MODES];
|
||||
};
|
||||
|
||||
struct kinc_wl_mouse {
|
||||
struct kinc_wl_seat *seat;
|
||||
int current_window;
|
||||
int x;
|
||||
int y;
|
||||
int enter_serial;
|
||||
const char *previous_cursor_name;
|
||||
struct wl_pointer *pointer;
|
||||
struct wl_surface *surface;
|
||||
bool hidden;
|
||||
bool locked;
|
||||
struct zwp_locked_pointer_v1 *lock;
|
||||
struct zwp_relative_pointer_v1 *relative;
|
||||
int serial;
|
||||
};
|
||||
|
||||
struct kinc_wl_keyboard {
|
||||
struct kinc_wl_seat *seat;
|
||||
struct wl_keyboard *keyboard;
|
||||
struct xkb_keymap *keymap;
|
||||
struct xkb_state *state;
|
||||
bool ctrlDown;
|
||||
|
||||
int repeat_delay;
|
||||
int repeat_rate;
|
||||
|
||||
int timerfd;
|
||||
|
||||
int last_key_code;
|
||||
int last_character;
|
||||
};
|
||||
|
||||
struct kinc_wl_data_offer {
|
||||
struct wl_data_offer *id;
|
||||
|
||||
int mime_type_count;
|
||||
char **mime_types;
|
||||
|
||||
uint32_t source_actions;
|
||||
uint32_t dnd_action;
|
||||
|
||||
void (*callback)(void *data, size_t data_size, void *user_data);
|
||||
void *user_data;
|
||||
int read_fd;
|
||||
|
||||
void *buffer;
|
||||
size_t buf_size;
|
||||
size_t buf_pos;
|
||||
|
||||
struct kinc_wl_data_offer *next;
|
||||
};
|
||||
|
||||
struct kinc_wl_data_source {
|
||||
struct wl_data_source *source;
|
||||
const char **mime_types;
|
||||
int num_mime_types;
|
||||
void *data;
|
||||
size_t data_size;
|
||||
};
|
||||
|
||||
struct kinc_wl_tablet_tool {
|
||||
struct zwp_tablet_tool_v2 *id;
|
||||
enum zwp_tablet_tool_v2_type type;
|
||||
uint32_t capabilities;
|
||||
uint64_t hardware_serial;
|
||||
uint64_t hardware_id_wacom;
|
||||
|
||||
int current_window;
|
||||
int x;
|
||||
int y;
|
||||
float current_pressure;
|
||||
float current_distance;
|
||||
|
||||
void (*press)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/);
|
||||
void (*move)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/);
|
||||
void (*release)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/);
|
||||
|
||||
struct kinc_wl_tablet_seat *seat;
|
||||
struct kinc_wl_tablet_tool *next;
|
||||
};
|
||||
|
||||
struct kinc_wl_tablet {
|
||||
struct zwp_tablet_v2 *id;
|
||||
struct kinc_wl_tablet_seat *seat;
|
||||
struct kinc_wl_tablet *next;
|
||||
};
|
||||
|
||||
struct kinc_wl_tablet_seat {
|
||||
struct zwp_tablet_seat_v2 *seat;
|
||||
struct kinc_wl_tablet *tablets;
|
||||
struct kinc_wl_tablet_tool *tablet_tools;
|
||||
};
|
||||
|
||||
struct kinc_wl_seat {
|
||||
struct wl_seat *seat;
|
||||
struct kinc_wl_keyboard keyboard;
|
||||
struct kinc_wl_mouse mouse;
|
||||
struct wl_touch *touch;
|
||||
struct kinc_wl_tablet_seat tablet_seat;
|
||||
struct wl_data_device *data_device;
|
||||
struct kinc_wl_data_offer *current_selection_offer;
|
||||
struct kinc_wl_data_offer *current_dnd_offer;
|
||||
int current_serial;
|
||||
uint32_t capabilities;
|
||||
char name[64];
|
||||
};
|
||||
|
||||
struct wayland_context {
|
||||
struct xkb_context *xkb_context;
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_shm *shm;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_subcompositor *subcompositor;
|
||||
struct wp_viewporter *viewporter;
|
||||
struct kinc_wl_seat seat;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct zxdg_decoration_manager_v1 *decoration_manager;
|
||||
struct wl_data_device_manager *data_device_manager;
|
||||
struct zwp_tablet_manager_v2 *tablet_manager;
|
||||
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||||
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
||||
struct wl_cursor_theme *cursor_theme;
|
||||
int cursor_size;
|
||||
int num_windows;
|
||||
struct kinc_wl_window windows[MAXIMUM_WINDOWS];
|
||||
int num_displays;
|
||||
struct kinc_wl_display displays[MAXIMUM_DISPLAYS];
|
||||
|
||||
struct kinc_wl_data_offer *data_offer_queue;
|
||||
};
|
||||
|
||||
extern struct wayland_context wl_ctx;
|
||||
|
||||
struct kinc_wl_data_source *kinc_wl_create_data_source(struct kinc_wl_seat *seat, const char *mime_types[], int num_mime_types, void *data, size_t data_size);
|
||||
void kinc_wl_data_source_destroy(struct kinc_wl_data_source *data_source);
|
||||
void kinc_wl_data_offer_accept(struct kinc_wl_data_offer *offer, void (*callback)(void *data, size_t data_size, void *user_data), void *user_data);
|
||||
void kinc_wl_destroy_data_offer(struct kinc_wl_data_offer *offer);
|
||||
void kinc_wayland_set_selection(struct kinc_wl_seat *seat, const char *text, int serial);
|
||||
void kinc_wayland_window_destroy(int window_index);
|
@ -0,0 +1,469 @@
|
||||
#include "wayland.h"
|
||||
|
||||
#include <kinc/image.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
// for all that shared memory stuff later on
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef KINC_EGL
|
||||
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
|
||||
static void xdg_surface_handle_configure(void *data, struct xdg_surface *surface, uint32_t serial) {
|
||||
xdg_surface_ack_configure(surface, serial);
|
||||
struct kinc_wl_window *window = data;
|
||||
window->configured = true;
|
||||
}
|
||||
|
||||
void kinc_internal_resize(int, int, int);
|
||||
void kinc_wayland_destroy_decoration(struct kinc_wl_decoration *);
|
||||
void kinc_wayland_resize_decoration(struct kinc_wl_decoration *, int x, int y, int width, int height);
|
||||
static void xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states) {
|
||||
struct kinc_wl_window *window = data;
|
||||
if ((width <= 0 || height <= 0) || (width == window->width + (KINC_WL_DECORATION_WIDTH * 2) &&
|
||||
height == window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT)) {
|
||||
return;
|
||||
}
|
||||
if (window->decorations.server_side) {
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
}
|
||||
else {
|
||||
window->width = width - (KINC_WL_DECORATION_WIDTH * 2);
|
||||
window->height = height - KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT;
|
||||
}
|
||||
|
||||
enum xdg_toplevel_state *state;
|
||||
wl_array_for_each(state, states) {
|
||||
switch (*state) {
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
kinc_internal_foreground_callback();
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
kinc_internal_resize(window->window_id, window->width, window->height);
|
||||
kinc_internal_call_resize_callback(window->window_id, window->width, window->height);
|
||||
if (window->decorations.server_side) {
|
||||
xdg_surface_set_window_geometry(window->xdg_surface, 0, 0, window->width, window->height);
|
||||
}
|
||||
else {
|
||||
xdg_surface_set_window_geometry(window->xdg_surface, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_TOP_Y,
|
||||
window->width + (KINC_WL_DECORATION_WIDTH * 2),
|
||||
window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT);
|
||||
}
|
||||
#ifdef KINC_EGL
|
||||
wl_egl_window_resize(window->egl_window, window->width, window->height, 0, 0);
|
||||
#endif
|
||||
|
||||
kinc_wayland_resize_decoration(&window->decorations.top, KINC_WL_DECORATION_TOP_X, KINC_WL_DECORATION_TOP_Y, KINC_WL_DECORATION_TOP_WIDTH,
|
||||
KINC_WL_DECORATION_TOP_HEIGHT);
|
||||
kinc_wayland_resize_decoration(&window->decorations.left, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_LEFT_Y, KINC_WL_DECORATION_LEFT_WIDTH,
|
||||
KINC_WL_DECORATION_LEFT_HEIGHT);
|
||||
kinc_wayland_resize_decoration(&window->decorations.right, KINC_WL_DECORATION_RIGHT_X, KINC_WL_DECORATION_RIGHT_Y, KINC_WL_DECORATION_RIGHT_WIDTH,
|
||||
KINC_WL_DECORATION_RIGHT_HEIGHT);
|
||||
kinc_wayland_resize_decoration(&window->decorations.bottom, KINC_WL_DECORATION_BOTTOM_X, KINC_WL_DECORATION_BOTTOM_Y, KINC_WL_DECORATION_BOTTOM_WIDTH,
|
||||
KINC_WL_DECORATION_BOTTOM_HEIGHT);
|
||||
kinc_wayland_resize_decoration(&window->decorations.close, KINC_WL_DECORATION_CLOSE_X, KINC_WL_DECORATION_CLOSE_Y, KINC_WL_DECORATION_CLOSE_WIDTH,
|
||||
KINC_WL_DECORATION_CLOSE_HEIGHT);
|
||||
}
|
||||
|
||||
void kinc_wayland_window_destroy(int window_index);
|
||||
|
||||
static void xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) {
|
||||
struct kinc_wl_window *window = data;
|
||||
if (kinc_internal_call_close_callback(window->window_id)) {
|
||||
kinc_window_destroy(window->window_id);
|
||||
if (wl_ctx.num_windows <= 0) {
|
||||
// no windows left, stop
|
||||
kinc_stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int create_shm_fd(off_t size) {
|
||||
int fd = -1;
|
||||
#if defined(__linux__)
|
||||
#if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 27)
|
||||
#else
|
||||
// memfd_create is available since glibc 2.27 and musl 1.1.20
|
||||
// the syscall is available since linux 3.17
|
||||
// at the time of writing (04/02/2022) these requirements are fullfilled for the "LTS" versions of the following distributions
|
||||
// Ubuntu 18.04
|
||||
// Debian Stretch
|
||||
// Alpine 3.12
|
||||
// Fedora 34
|
||||
|
||||
fd = memfd_create("kinc-wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd >= 0) {
|
||||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||||
int ret = posix_fallocate(fd, 0, size);
|
||||
if (ret != 0) {
|
||||
close(fd);
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else // fall back to a temp file
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
|
||||
static const char template[] = "/kinc-shared-XXXXXX";
|
||||
|
||||
const char *path = getenv("XDG_RUNTIME_DIR");
|
||||
if (!path) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *name = malloc(strlen(path) + sizeof(template));
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
fd = mkostemp(name, O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
unlink(name);
|
||||
|
||||
free(name);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
int ret = ftruncate(fd, size);
|
||||
if (ret != 0) {
|
||||
close(fd);
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct wl_buffer *kinc_wayland_create_shm_buffer(const kinc_image_t *image) {
|
||||
int stride = image->width * 4;
|
||||
int length = image->width * image->height * 4;
|
||||
|
||||
const int fd = create_shm_fd(length);
|
||||
if (fd < 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland: Creating a buffer file for %d B failed: %s", length, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland: mmap failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(wl_ctx.shm, fd, length);
|
||||
|
||||
close(fd);
|
||||
memcpy(data, image->data, image->width * image->height * 4);
|
||||
|
||||
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, image->width, image->height, stride, WL_SHM_FORMAT_ARGB8888);
|
||||
munmap(data, length);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int grey_data[] = {0xFF333333};
|
||||
|
||||
static int close_data[] = {
|
||||
0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000,
|
||||
0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
// image format is argb32, but kinc does not have that, so let's lie to it
|
||||
|
||||
static kinc_image_t grey_image = {
|
||||
1, 1, 0, KINC_IMAGE_FORMAT_RGBA32, 0, KINC_IMAGE_COMPRESSION_NONE, grey_data, sizeof(grey_data),
|
||||
};
|
||||
static kinc_image_t close_image = {
|
||||
9, 9, 0, KINC_IMAGE_FORMAT_RGBA32, 0, KINC_IMAGE_COMPRESSION_NONE, close_data, sizeof(close_data),
|
||||
};
|
||||
|
||||
void kinc_wayland_create_decoration(struct kinc_wl_decoration *decoration, struct wl_surface *parent, struct wl_buffer *buffer, bool opaque, int x, int y,
|
||||
int width, int height) {
|
||||
decoration->surface = wl_compositor_create_surface(wl_ctx.compositor);
|
||||
decoration->subsurface = wl_subcompositor_get_subsurface(wl_ctx.subcompositor, decoration->surface, parent);
|
||||
wl_subsurface_set_position(decoration->subsurface, x, y);
|
||||
decoration->viewport = wp_viewporter_get_viewport(wl_ctx.viewporter, decoration->surface);
|
||||
wp_viewport_set_destination(decoration->viewport, width, height);
|
||||
if (buffer)
|
||||
wl_surface_attach(decoration->surface, buffer, 0, 0);
|
||||
|
||||
if (opaque) {
|
||||
struct wl_region *region = wl_compositor_create_region(wl_ctx.compositor);
|
||||
wl_region_add(region, 0, 0, width, height);
|
||||
wl_surface_set_opaque_region(decoration->surface, region);
|
||||
wl_surface_commit(decoration->surface);
|
||||
wl_region_destroy(region);
|
||||
}
|
||||
else
|
||||
wl_surface_commit(decoration->surface);
|
||||
}
|
||||
|
||||
void kinc_wayland_resize_decoration(struct kinc_wl_decoration *decoration, int x, int y, int width, int height) {
|
||||
if (decoration->surface) {
|
||||
wl_subsurface_set_position(decoration->subsurface, x, y);
|
||||
wp_viewport_set_destination(decoration->viewport, width, height);
|
||||
wl_surface_commit(decoration->surface);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_wayland_destroy_decoration(struct kinc_wl_decoration *decoration) {
|
||||
if (decoration->subsurface)
|
||||
wl_subsurface_destroy(decoration->subsurface);
|
||||
if (decoration->surface)
|
||||
wl_surface_destroy(decoration->surface);
|
||||
if (decoration->viewport)
|
||||
wp_viewport_destroy(decoration->viewport);
|
||||
decoration->surface = NULL;
|
||||
decoration->subsurface = NULL;
|
||||
decoration->viewport = NULL;
|
||||
}
|
||||
|
||||
void kinc_wayland_destroy_decorations(struct kinc_wl_window *window) {
|
||||
kinc_wayland_destroy_decoration(&window->decorations.top);
|
||||
kinc_wayland_destroy_decoration(&window->decorations.left);
|
||||
kinc_wayland_destroy_decoration(&window->decorations.right);
|
||||
kinc_wayland_destroy_decoration(&window->decorations.bottom);
|
||||
kinc_wayland_destroy_decoration(&window->decorations.close);
|
||||
}
|
||||
|
||||
void kinc_wayland_create_decorations(struct kinc_wl_window *window) {
|
||||
if (!window->decorations.dec_buffer) {
|
||||
window->decorations.dec_buffer = kinc_wayland_create_shm_buffer(&grey_image);
|
||||
window->decorations.close_buffer = kinc_wayland_create_shm_buffer(&close_image);
|
||||
window->decorations.max_buffer = kinc_wayland_create_shm_buffer(&grey_image);
|
||||
window->decorations.min_buffer = kinc_wayland_create_shm_buffer(&grey_image);
|
||||
}
|
||||
kinc_wayland_create_decoration(&window->decorations.top, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_TOP_X,
|
||||
KINC_WL_DECORATION_TOP_Y, KINC_WL_DECORATION_TOP_WIDTH, KINC_WL_DECORATION_TOP_HEIGHT);
|
||||
kinc_wayland_create_decoration(&window->decorations.left, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_LEFT_X,
|
||||
KINC_WL_DECORATION_LEFT_Y, KINC_WL_DECORATION_LEFT_WIDTH, KINC_WL_DECORATION_LEFT_HEIGHT);
|
||||
kinc_wayland_create_decoration(&window->decorations.right, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_RIGHT_X,
|
||||
KINC_WL_DECORATION_RIGHT_Y, KINC_WL_DECORATION_RIGHT_WIDTH, KINC_WL_DECORATION_RIGHT_HEIGHT);
|
||||
kinc_wayland_create_decoration(&window->decorations.bottom, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_BOTTOM_X,
|
||||
KINC_WL_DECORATION_BOTTOM_Y, KINC_WL_DECORATION_BOTTOM_WIDTH, KINC_WL_DECORATION_BOTTOM_HEIGHT);
|
||||
kinc_wayland_create_decoration(&window->decorations.close, window->surface, window->decorations.close_buffer, true, KINC_WL_DECORATION_CLOSE_X,
|
||||
KINC_WL_DECORATION_CLOSE_Y, KINC_WL_DECORATION_CLOSE_WIDTH, KINC_WL_DECORATION_CLOSE_HEIGHT);
|
||||
}
|
||||
|
||||
void xdg_toplevel_decoration_configure(void *data, struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) {
|
||||
struct kinc_wl_window *window = data;
|
||||
|
||||
if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) {
|
||||
window->decorations.server_side = false;
|
||||
if (window->decorations.top.surface) {
|
||||
kinc_wayland_destroy_decorations(window);
|
||||
}
|
||||
if (window->mode == KINC_WINDOW_MODE_WINDOW) {
|
||||
kinc_wayland_create_decorations(window);
|
||||
}
|
||||
}
|
||||
else if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) {
|
||||
window->decorations.server_side = true;
|
||||
if (window->decorations.top.surface) {
|
||||
kinc_wayland_destroy_decorations(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wl_surface_handle_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) {
|
||||
struct kinc_wl_window *window = wl_surface_get_user_data(wl_surface);
|
||||
struct kinc_wl_display *display = wl_output_get_user_data(output);
|
||||
|
||||
if (display && window) {
|
||||
window->display_index = display->index;
|
||||
}
|
||||
}
|
||||
|
||||
void wl_surface_handle_leave(void *data, struct wl_surface *wl_surface, struct wl_output *output) {}
|
||||
|
||||
static const struct wl_surface_listener wl_surface_listener = {
|
||||
wl_surface_handle_enter,
|
||||
wl_surface_handle_leave,
|
||||
};
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
xdg_surface_handle_configure,
|
||||
};
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
xdg_toplevel_handle_configure,
|
||||
xdg_toplevel_handle_close,
|
||||
};
|
||||
|
||||
static const struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = {
|
||||
xdg_toplevel_decoration_configure,
|
||||
};
|
||||
|
||||
void kinc_wayland_window_set_title(int window_index, const char *title);
|
||||
void kinc_wayland_window_change_mode(int window_index, kinc_window_mode_t mode);
|
||||
|
||||
int kinc_wayland_window_create(kinc_window_options_t *win, kinc_framebuffer_options_t *frame) {
|
||||
int window_index = -1;
|
||||
for (int i = 0; i < MAXIMUM_WINDOWS; i++) {
|
||||
if (wl_ctx.windows[i].surface == NULL) {
|
||||
window_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (window_index == -1) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Too much windows (maximum is %i)", MAXIMUM_WINDOWS);
|
||||
exit(1);
|
||||
}
|
||||
struct kinc_wl_window *window = &wl_ctx.windows[window_index];
|
||||
window->window_id = window_index;
|
||||
window->width = win->width;
|
||||
window->height = win->height;
|
||||
window->mode = KINC_WINDOW_MODE_WINDOW;
|
||||
window->surface = wl_compositor_create_surface(wl_ctx.compositor);
|
||||
wl_surface_set_user_data(window->surface, window);
|
||||
wl_surface_add_listener(window->surface, &wl_surface_listener, NULL);
|
||||
|
||||
window->xdg_surface = xdg_wm_base_get_xdg_surface(wl_ctx.xdg_wm_base, window->surface);
|
||||
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
|
||||
|
||||
window->toplevel = xdg_surface_get_toplevel(window->xdg_surface);
|
||||
xdg_toplevel_add_listener(window->toplevel, &xdg_toplevel_listener, window);
|
||||
|
||||
kinc_wayland_window_set_title(window_index, win->title);
|
||||
|
||||
if (wl_ctx.decoration_manager) {
|
||||
window->xdg_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(wl_ctx.decoration_manager, window->toplevel);
|
||||
#ifdef KINC_WAYLAND_FORCE_CSD
|
||||
zxdg_toplevel_decoration_v1_set_mode(window->xdg_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
|
||||
#endif
|
||||
zxdg_toplevel_decoration_v1_add_listener(window->xdg_decoration, &xdg_toplevel_decoration_listener, window);
|
||||
}
|
||||
else {
|
||||
window->decorations.server_side = false;
|
||||
kinc_wayland_create_decorations(window);
|
||||
}
|
||||
|
||||
#ifdef KINC_EGL
|
||||
window->egl_window = wl_egl_window_create(window->surface, window->width, window->height);
|
||||
#endif
|
||||
wl_surface_commit(window->surface);
|
||||
kinc_wayland_window_change_mode(window_index, win->mode);
|
||||
wl_ctx.num_windows++;
|
||||
|
||||
while (!window->configured) {
|
||||
wl_display_roundtrip(wl_ctx.display);
|
||||
}
|
||||
|
||||
return window_index;
|
||||
}
|
||||
|
||||
void kinc_wayland_window_destroy(int window_index) {
|
||||
struct kinc_wl_window *window = &wl_ctx.windows[window_index];
|
||||
#ifdef KINC_EGL
|
||||
wl_egl_window_destroy(window->egl_window);
|
||||
#endif
|
||||
if (window->xdg_decoration) {
|
||||
zxdg_toplevel_decoration_v1_destroy(window->xdg_decoration);
|
||||
}
|
||||
|
||||
xdg_toplevel_destroy(window->toplevel);
|
||||
xdg_surface_destroy(window->xdg_surface);
|
||||
wl_surface_destroy(window->surface);
|
||||
*window = (struct kinc_wl_window){0};
|
||||
wl_ctx.num_windows--;
|
||||
}
|
||||
|
||||
void kinc_wayland_window_set_title(int window_index, const char *title) {
|
||||
struct kinc_wl_window *window = &wl_ctx.windows[window_index];
|
||||
xdg_toplevel_set_title(window->toplevel, title == NULL ? "" : title);
|
||||
}
|
||||
|
||||
int kinc_wayland_window_x(int window_index) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support getting the window position.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kinc_wayland_window_y(int window_index) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support getting the window position.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kinc_wayland_window_move(int window_index, int x, int y) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support setting the window position.");
|
||||
}
|
||||
|
||||
int kinc_wayland_window_width(int window_index) {
|
||||
return wl_ctx.windows[window_index].width;
|
||||
}
|
||||
|
||||
int kinc_wayland_window_height(int window_index) {
|
||||
return wl_ctx.windows[window_index].height;
|
||||
}
|
||||
|
||||
void kinc_wayland_window_resize(int window_index, int width, int height) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "TODO: resizing windows");
|
||||
}
|
||||
|
||||
void kinc_wayland_window_show(int window_index) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support unhiding windows.");
|
||||
}
|
||||
|
||||
void kinc_wayland_window_hide(int window_index) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support hiding windows.");
|
||||
}
|
||||
|
||||
kinc_window_mode_t kinc_wayland_window_get_mode(int window_index) {
|
||||
return wl_ctx.windows[window_index].mode;
|
||||
}
|
||||
|
||||
void kinc_wayland_window_change_mode(int window_index, kinc_window_mode_t mode) {
|
||||
struct kinc_wl_window *window = &wl_ctx.windows[window_index];
|
||||
if (mode == window->mode) {
|
||||
return;
|
||||
}
|
||||
switch (mode) {
|
||||
case KINC_WINDOW_MODE_WINDOW:
|
||||
if (window->mode == KINC_WINDOW_MODE_FULLSCREEN || window->mode == KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
|
||||
window->mode = KINC_WINDOW_MODE_WINDOW;
|
||||
xdg_toplevel_unset_fullscreen(window->toplevel);
|
||||
}
|
||||
break;
|
||||
case KINC_WINDOW_MODE_FULLSCREEN:
|
||||
case KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
|
||||
if (window->mode == KINC_WINDOW_MODE_WINDOW) {
|
||||
window->mode = mode;
|
||||
struct kinc_wl_display *display = &wl_ctx.displays[window->display_index];
|
||||
xdg_toplevel_set_fullscreen(window->toplevel, display->output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int kinc_wayland_window_display(int window_index) {
|
||||
struct kinc_wl_window *window = &wl_ctx.windows[window_index];
|
||||
return window->display_index;
|
||||
}
|
||||
|
||||
int kinc_wayland_count_windows() {
|
||||
return wl_ctx.num_windows;
|
||||
}
|
140
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/window.c.h
Normal file
140
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/window.c.h
Normal file
@ -0,0 +1,140 @@
|
||||
#include "funcs.h"
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef KINC_EGL
|
||||
EGLDisplay kinc_egl_get_display() {
|
||||
return procs.egl_get_display();
|
||||
}
|
||||
EGLNativeWindowType kinc_egl_get_native_window(EGLDisplay display, EGLConfig config, int window_index) {
|
||||
return procs.egl_get_native_window(display, config, window_index);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KINC_VULKAN
|
||||
void kinc_vulkan_get_instance_extensions(const char **extensions, int *count, int max) {
|
||||
procs.vulkan_get_instance_extensions(extensions, count, max);
|
||||
}
|
||||
|
||||
VkBool32 kinc_vulkan_get_physical_device_presentation_support(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex) {
|
||||
return procs.vulkan_get_physical_device_presentation_support(physicalDevice, queueFamilyIndex);
|
||||
}
|
||||
VkResult kinc_vulkan_create_surface(VkInstance instance, int window_index, VkSurfaceKHR *surface) {
|
||||
return procs.vulkan_create_surface(instance, window_index, surface);
|
||||
}
|
||||
#endif
|
||||
|
||||
int kinc_count_windows(void) {
|
||||
return procs.count_windows();
|
||||
}
|
||||
|
||||
int kinc_window_x(int window_index) {
|
||||
return procs.window_x(window_index);
|
||||
}
|
||||
|
||||
int kinc_window_y(int window_index) {
|
||||
return procs.window_y(window_index);
|
||||
}
|
||||
|
||||
int kinc_window_width(int window_index) {
|
||||
return procs.window_width(window_index);
|
||||
}
|
||||
|
||||
int kinc_window_height(int window_index) {
|
||||
return procs.window_height(window_index);
|
||||
}
|
||||
|
||||
void kinc_window_resize(int window_index, int width, int height) {
|
||||
procs.window_resize(window_index, width, height);
|
||||
}
|
||||
|
||||
void kinc_window_move(int window_index, int x, int y) {
|
||||
procs.window_move(window_index, x, y);
|
||||
}
|
||||
|
||||
void kinc_window_change_framebuffer(int window_index, kinc_framebuffer_options_t *frame) {}
|
||||
|
||||
void kinc_window_change_features(int window_index, int features) {}
|
||||
|
||||
void kinc_window_change_mode(int window_index, kinc_window_mode_t mode) {
|
||||
procs.window_change_mode(window_index, mode);
|
||||
}
|
||||
|
||||
int kinc_window_display(int window_index) {
|
||||
return procs.window_display(window_index);
|
||||
}
|
||||
|
||||
void kinc_window_destroy(int window_index) {
|
||||
kinc_g4_internal_destroy_window(window_index);
|
||||
procs.window_destroy(window_index);
|
||||
}
|
||||
|
||||
void kinc_window_show(int window_index) {
|
||||
procs.window_show(window_index);
|
||||
}
|
||||
|
||||
void kinc_window_hide(int window_index) {
|
||||
procs.window_hide(window_index);
|
||||
}
|
||||
|
||||
void kinc_window_set_title(int window_index, const char *title) {
|
||||
procs.window_set_title(window_index, title);
|
||||
}
|
||||
|
||||
int kinc_window_create(kinc_window_options_t *win, kinc_framebuffer_options_t *frame) {
|
||||
int index = procs.window_create(win, frame);
|
||||
kinc_g4_internal_init_window(index, frame->depth_bits, frame->stencil_bits, frame->vertical_sync);
|
||||
return index;
|
||||
}
|
||||
|
||||
static struct {
|
||||
void (*resize_callback)(int width, int height, void *data);
|
||||
void *resize_data;
|
||||
void (*ppi_callback)(int ppi, void *data);
|
||||
void *ppi_data;
|
||||
bool (*close_callback)(void *data);
|
||||
void *close_data;
|
||||
} kinc_internal_window_callbacks[16];
|
||||
|
||||
void kinc_window_set_resize_callback(int window_index, void (*callback)(int width, int height, void *data), void *data) {
|
||||
kinc_internal_window_callbacks[window_index].resize_callback = callback;
|
||||
kinc_internal_window_callbacks[window_index].resize_data = data;
|
||||
}
|
||||
|
||||
void kinc_internal_call_resize_callback(int window_index, int width, int height) {
|
||||
if (kinc_internal_window_callbacks[window_index].resize_callback != NULL) {
|
||||
kinc_internal_window_callbacks[window_index].resize_callback(width, height, kinc_internal_window_callbacks[window_index].resize_data);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_window_set_ppi_changed_callback(int window_index, void (*callback)(int ppi, void *data), void *data) {
|
||||
kinc_internal_window_callbacks[window_index].ppi_callback = callback;
|
||||
kinc_internal_window_callbacks[window_index].ppi_data = data;
|
||||
}
|
||||
|
||||
void kinc_internal_call_ppi_changed_callback(int window_index, int ppi) {
|
||||
if (kinc_internal_window_callbacks[window_index].ppi_callback != NULL) {
|
||||
kinc_internal_window_callbacks[window_index].ppi_callback(ppi, kinc_internal_window_callbacks[window_index].resize_data);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_window_set_close_callback(int window_index, bool (*callback)(void *data), void *data) {
|
||||
kinc_internal_window_callbacks[window_index].close_callback = callback;
|
||||
kinc_internal_window_callbacks[window_index].close_data = data;
|
||||
}
|
||||
|
||||
bool kinc_internal_call_close_callback(int window_index) {
|
||||
if (kinc_internal_window_callbacks[window_index].close_callback != NULL) {
|
||||
return kinc_internal_window_callbacks[window_index].close_callback(kinc_internal_window_callbacks[window_index].close_data);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
kinc_window_mode_t kinc_window_get_mode(int window_index) {
|
||||
return procs.window_get_mode(window_index);
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
|
||||
#include "x11.h"
|
||||
#include <string.h>
|
||||
|
||||
// TODO: deal with monitor hotplugging and such
|
||||
|
||||
void kinc_x11_display_init(void) {
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
|
||||
bool hasXinerama = (xlib.XineramaQueryExtension(x11_ctx.display, &eventBase, &errorBase) && xlib.XineramaIsActive(x11_ctx.display));
|
||||
XineramaScreenInfo *xinerama_screens = NULL;
|
||||
int xinerama_screen_count = 0;
|
||||
if (hasXinerama) {
|
||||
xinerama_screens = xlib.XineramaQueryScreens(x11_ctx.display, &xinerama_screen_count);
|
||||
}
|
||||
|
||||
Window root_window = RootWindow(x11_ctx.display, DefaultScreen(x11_ctx.display));
|
||||
XRRScreenResources *screen_resources = xlib.XRRGetScreenResourcesCurrent(x11_ctx.display, root_window);
|
||||
RROutput primary_output = xlib.XRRGetOutputPrimary(x11_ctx.display, root_window);
|
||||
|
||||
for (int i = 0; i < screen_resources->noutput; i++) {
|
||||
if (i >= MAXIMUM_DISPLAYS) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Too many screens (maximum %i)", MAXIMUM_DISPLAYS);
|
||||
break;
|
||||
}
|
||||
|
||||
XRROutputInfo *output_info = xlib.XRRGetOutputInfo(x11_ctx.display, screen_resources, screen_resources->outputs[i]);
|
||||
if (output_info->connection != RR_Connected || output_info->crtc == None) {
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
XRRCrtcInfo *crtc_info = xlib.XRRGetCrtcInfo(x11_ctx.display, screen_resources, output_info->crtc);
|
||||
|
||||
struct kinc_x11_display *display = &x11_ctx.displays[x11_ctx.num_displays++];
|
||||
display->index = i;
|
||||
strncpy(display->name, output_info->name, sizeof(display->name));
|
||||
display->x = crtc_info->x;
|
||||
display->y = crtc_info->y;
|
||||
display->width = crtc_info->width;
|
||||
display->height = crtc_info->height;
|
||||
display->primary = screen_resources->outputs[i] == primary_output;
|
||||
display->crtc = output_info->crtc;
|
||||
display->output = screen_resources->outputs[i];
|
||||
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeCrtcInfo(crtc_info);
|
||||
}
|
||||
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
if (hasXinerama) {
|
||||
xlib.XFree(xinerama_screens);
|
||||
}
|
||||
}
|
||||
|
||||
int kinc_x11_display_primary(void) {
|
||||
for (int i = 0; i < x11_ctx.num_displays; i++) {
|
||||
if (x11_ctx.displays[i].primary) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kinc_x11_count_displays(void) {
|
||||
return x11_ctx.num_displays;
|
||||
}
|
||||
|
||||
bool kinc_x11_display_available(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return x11_ctx.displays[display_index].output != None;
|
||||
}
|
||||
|
||||
const char *kinc_x11_display_name(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return x11_ctx.displays[display_index].name;
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_x11_display_current_mode(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_x11_display *display = &x11_ctx.displays[display_index];
|
||||
kinc_display_mode_t mode;
|
||||
mode.x = 0;
|
||||
mode.y = 0;
|
||||
mode.width = display->width;
|
||||
mode.height = display->height;
|
||||
mode.frequency = 60;
|
||||
mode.bits_per_pixel = 32;
|
||||
mode.pixels_per_inch = 96;
|
||||
|
||||
Window root_window = DefaultRootWindow(x11_ctx.display);
|
||||
XRRScreenResources *screen_resources = xlib.XRRGetScreenResourcesCurrent(x11_ctx.display, root_window);
|
||||
|
||||
XRROutputInfo *output_info = xlib.XRRGetOutputInfo(x11_ctx.display, screen_resources, screen_resources->outputs[display->index]);
|
||||
if (output_info->connection != RR_Connected || output_info->crtc == None) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Display %i not connected.", display_index);
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
return mode;
|
||||
}
|
||||
|
||||
XRRCrtcInfo *crtc_info = xlib.XRRGetCrtcInfo(x11_ctx.display, screen_resources, output_info->crtc);
|
||||
for (int j = 0; j < output_info->nmode; j++) {
|
||||
RRMode rr_mode = crtc_info->mode;
|
||||
XRRModeInfo *mode_info = NULL;
|
||||
for (int k = 0; k < screen_resources->nmode; k++) {
|
||||
if (screen_resources->modes[k].id == rr_mode) {
|
||||
mode_info = &screen_resources->modes[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode_info == NULL) {
|
||||
continue;
|
||||
}
|
||||
mode.x = display->x;
|
||||
mode.y = display->y;
|
||||
mode.width = mode_info->width;
|
||||
mode.height = mode_info->height;
|
||||
mode.pixels_per_inch = 96;
|
||||
mode.bits_per_pixel = 32;
|
||||
if (mode_info->hTotal && mode_info->vTotal) {
|
||||
mode.frequency = (mode_info->dotClock / (mode_info->hTotal * mode_info->vTotal));
|
||||
}
|
||||
else {
|
||||
mode.frequency = 60;
|
||||
}
|
||||
}
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeCrtcInfo(crtc_info);
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
return mode;
|
||||
}
|
||||
|
||||
int kinc_x11_display_count_available_modes(int display_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_x11_display *display = &x11_ctx.displays[display_index];
|
||||
|
||||
Window root_window = RootWindow(x11_ctx.display, DefaultScreen(x11_ctx.display));
|
||||
XRRScreenResources *screen_resources = xlib.XRRGetScreenResourcesCurrent(x11_ctx.display, root_window);
|
||||
|
||||
XRROutputInfo *output_info = xlib.XRRGetOutputInfo(x11_ctx.display, screen_resources, screen_resources->outputs[display->index]);
|
||||
if (output_info->connection != RR_Connected || output_info->crtc == None) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Display %i not connected.", display_index);
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int num_modes = output_info->nmode;
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
return num_modes;
|
||||
}
|
||||
|
||||
kinc_display_mode_t kinc_x11_display_available_mode(int display_index, int mode_index) {
|
||||
if (display_index >= MAXIMUM_DISPLAYS)
|
||||
display_index = 0;
|
||||
struct kinc_x11_display *display = &x11_ctx.displays[display_index];
|
||||
kinc_display_mode_t mode;
|
||||
mode.x = 0;
|
||||
mode.y = 0;
|
||||
mode.width = display->width;
|
||||
mode.height = display->height;
|
||||
mode.frequency = 60;
|
||||
mode.bits_per_pixel = 32;
|
||||
mode.pixels_per_inch = 96;
|
||||
|
||||
Window root_window = RootWindow(x11_ctx.display, DefaultScreen(x11_ctx.display));
|
||||
XRRScreenResources *screen_resources = xlib.XRRGetScreenResourcesCurrent(x11_ctx.display, root_window);
|
||||
|
||||
XRROutputInfo *output_info = xlib.XRRGetOutputInfo(x11_ctx.display, screen_resources, screen_resources->outputs[display->index]);
|
||||
if (output_info->connection != RR_Connected || output_info->crtc == None) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Display %i not connected.", display_index);
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
return mode;
|
||||
}
|
||||
|
||||
if (mode_index >= output_info->nmode) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Invalid mode index %i.", mode_index);
|
||||
}
|
||||
|
||||
RRMode rr_mode = output_info->modes[mode_index];
|
||||
XRRModeInfo *mode_info = NULL;
|
||||
|
||||
for (int k = 0; k < screen_resources->nmode; k++) {
|
||||
if (screen_resources->modes[k].id == rr_mode) {
|
||||
mode_info = &screen_resources->modes[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode_info != NULL) {
|
||||
mode.x = display->x;
|
||||
mode.y = display->y;
|
||||
mode.width = mode_info->width;
|
||||
mode.height = mode_info->height;
|
||||
mode.pixels_per_inch = 96;
|
||||
mode.bits_per_pixel = 32;
|
||||
if (mode_info->hTotal && mode_info->vTotal) {
|
||||
mode.frequency = (mode_info->dotClock / (mode_info->hTotal * mode_info->vTotal));
|
||||
}
|
||||
else {
|
||||
mode.frequency = 60;
|
||||
}
|
||||
}
|
||||
|
||||
xlib.XRRFreeOutputInfo(output_info);
|
||||
xlib.XRRFreeScreenResources(screen_resources);
|
||||
return mode;
|
||||
}
|
1055
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/x11/system.c.h
Normal file
1055
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/x11/system.c.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,206 @@
|
||||
#include "x11.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct MwmHints {
|
||||
// These correspond to XmRInt resources. (VendorSE.c)
|
||||
int flags;
|
||||
int functions;
|
||||
int decorations;
|
||||
int input_mode;
|
||||
int status;
|
||||
};
|
||||
#define MWM_HINTS_DECORATIONS (1L << 1)
|
||||
|
||||
void kinc_x11_window_set_title(int window_index, const char *title);
|
||||
void kinc_x11_window_change_mode(int window_index, kinc_window_mode_t mode);
|
||||
|
||||
int kinc_x11_window_create(kinc_window_options_t *win, kinc_framebuffer_options_t *frame) {
|
||||
int window_index = -1;
|
||||
for (int i = 0; i < MAXIMUM_WINDOWS; i++) {
|
||||
if (x11_ctx.windows[i].window == None) {
|
||||
window_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (window_index == -1) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Too much windows (maximum is %i)", MAXIMUM_WINDOWS);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
window->window_index = window_index;
|
||||
window->width = win->width;
|
||||
window->height = win->height;
|
||||
|
||||
Visual *visual = NULL;
|
||||
XSetWindowAttributes set_window_attribs = {0};
|
||||
|
||||
set_window_attribs.border_pixel = 0;
|
||||
set_window_attribs.event_mask =
|
||||
KeyPressMask | KeyReleaseMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask;
|
||||
int screen = DefaultScreen(x11_ctx.display);
|
||||
visual = DefaultVisual(x11_ctx.display, screen);
|
||||
int depth = DefaultDepth(x11_ctx.display, screen);
|
||||
set_window_attribs.colormap = xlib.XCreateColormap(x11_ctx.display, RootWindow(x11_ctx.display, screen), visual, AllocNone);
|
||||
window->window = xlib.XCreateWindow(x11_ctx.display, RootWindow(x11_ctx.display, DefaultScreen(x11_ctx.display)), 0, 0, win->width, win->height, 0, depth,
|
||||
InputOutput, visual, CWBorderPixel | CWColormap | CWEventMask, &set_window_attribs);
|
||||
|
||||
static char nameClass[256];
|
||||
static const char *nameClassAddendum = "_KincApplication";
|
||||
strncpy(nameClass, kinc_application_name(), sizeof(nameClass) - strlen(nameClassAddendum) - 1);
|
||||
strcat(nameClass, nameClassAddendum);
|
||||
char resNameBuffer[256];
|
||||
strncpy(resNameBuffer, kinc_application_name(), 256);
|
||||
XClassHint classHint = {.res_name = resNameBuffer, .res_class = nameClass};
|
||||
xlib.XSetClassHint(x11_ctx.display, window->window, &classHint);
|
||||
|
||||
xlib.XSetLocaleModifiers("@im=none");
|
||||
window->xInputMethod = xlib.XOpenIM(x11_ctx.display, NULL, NULL, NULL);
|
||||
window->xInputContext = xlib.XCreateIC(window->xInputMethod, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, window->window, NULL);
|
||||
xlib.XSetICFocus(window->xInputContext);
|
||||
|
||||
window->mode = KINC_WINDOW_MODE_WINDOW;
|
||||
kinc_x11_window_change_mode(window_index, win->mode);
|
||||
|
||||
xlib.XMapWindow(x11_ctx.display, window->window);
|
||||
|
||||
Atom XdndVersion = 5;
|
||||
xlib.XChangeProperty(x11_ctx.display, window->window, x11_ctx.atoms.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XdndVersion, 1);
|
||||
xlib.XSetWMProtocols(x11_ctx.display, window->window, &x11_ctx.atoms.WM_DELETE_WINDOW, 1);
|
||||
|
||||
kinc_x11_window_set_title(window_index, win->title);
|
||||
|
||||
if (x11_ctx.pen.id != -1) {
|
||||
xlib.XSelectExtensionEvent(x11_ctx.display, window->window, &x11_ctx.pen.motionClass, 1);
|
||||
}
|
||||
|
||||
if (x11_ctx.eraser.id != -1) {
|
||||
xlib.XSelectExtensionEvent(x11_ctx.display, window->window, &x11_ctx.eraser.motionClass, 1);
|
||||
}
|
||||
|
||||
x11_ctx.num_windows++;
|
||||
return window_index;
|
||||
}
|
||||
|
||||
void kinc_x11_window_destroy(int window_index) {
|
||||
xlib.XFlush(x11_ctx.display);
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
xlib.XDestroyIC(window->xInputContext);
|
||||
xlib.XCloseIM(window->xInputMethod);
|
||||
xlib.XDestroyWindow(x11_ctx.display, window->window);
|
||||
xlib.XFlush(x11_ctx.display);
|
||||
*window = (struct kinc_x11_window){0};
|
||||
x11_ctx.num_windows--;
|
||||
}
|
||||
|
||||
void kinc_x11_window_set_title(int window_index, const char *_title) {
|
||||
const char *title = _title == NULL ? "" : _title;
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
xlib.XChangeProperty(x11_ctx.display, window->window, x11_ctx.atoms.NET_WM_NAME, x11_ctx.atoms.UTF8_STRING, 8, PropModeReplace, (unsigned char *)title,
|
||||
strlen(title));
|
||||
|
||||
xlib.XChangeProperty(x11_ctx.display, window->window, x11_ctx.atoms.NET_WM_ICON_NAME, x11_ctx.atoms.UTF8_STRING, 8, PropModeReplace, (unsigned char *)title,
|
||||
strlen(title));
|
||||
|
||||
xlib.XFlush(x11_ctx.display);
|
||||
}
|
||||
|
||||
int kinc_x11_window_x(int window_index) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "x11 does not support getting the window position.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kinc_x11_window_y(int window_index) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "x11 does not support getting the window position.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kinc_x11_window_move(int window_index, int x, int y) {
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
xlib.XMoveWindow(x11_ctx.display, window->window, x, y);
|
||||
}
|
||||
|
||||
int kinc_x11_window_width(int window_index) {
|
||||
return x11_ctx.windows[window_index].width;
|
||||
}
|
||||
|
||||
int kinc_x11_window_height(int window_index) {
|
||||
return x11_ctx.windows[window_index].height;
|
||||
}
|
||||
|
||||
void kinc_x11_window_resize(int window_index, int width, int height) {
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
xlib.XResizeWindow(x11_ctx.display, window->window, width, height);
|
||||
}
|
||||
|
||||
void kinc_x11_window_show(int window_index) {
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
xlib.XMapWindow(x11_ctx.display, window->window);
|
||||
}
|
||||
|
||||
void kinc_x11_window_hide(int window_index) {
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
xlib.XUnmapWindow(x11_ctx.display, window->window);
|
||||
}
|
||||
|
||||
kinc_window_mode_t kinc_x11_window_get_mode(int window_index) {
|
||||
return x11_ctx.windows[window_index].mode;
|
||||
}
|
||||
|
||||
void kinc_x11_window_change_mode(int window_index, kinc_window_mode_t mode) {
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
if (mode == window->mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool fullscreen = false;
|
||||
|
||||
switch (mode) {
|
||||
case KINC_WINDOW_MODE_WINDOW:
|
||||
if (window->mode == KINC_WINDOW_MODE_FULLSCREEN) {
|
||||
window->mode = KINC_WINDOW_MODE_WINDOW;
|
||||
fullscreen = false;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case KINC_WINDOW_MODE_FULLSCREEN:
|
||||
case KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
|
||||
if (window->mode == KINC_WINDOW_MODE_WINDOW) {
|
||||
window->mode = KINC_WINDOW_MODE_FULLSCREEN;
|
||||
fullscreen = true;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
XEvent xev;
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = window->window;
|
||||
xev.xclient.message_type = x11_ctx.atoms.NET_WM_STATE;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = fullscreen ? 1 : 0;
|
||||
xev.xclient.data.l[1] = x11_ctx.atoms.NET_WM_STATE_FULLSCREEN;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
xlib.XMapWindow(x11_ctx.display, window->window);
|
||||
|
||||
xlib.XSendEvent(x11_ctx.display, DefaultRootWindow(x11_ctx.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
||||
|
||||
xlib.XFlush(x11_ctx.display);
|
||||
}
|
||||
|
||||
int kinc_x11_window_display(int window_index) {
|
||||
struct kinc_x11_window *window = &x11_ctx.windows[window_index];
|
||||
return window->display_index;
|
||||
}
|
||||
|
||||
int kinc_x11_count_windows() {
|
||||
return x11_ctx.num_windows;
|
||||
}
|
200
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/x11/x11.h
Normal file
200
Kha/Kinc/Backends/System/Linux/Sources/kinc/backend/x11/x11.h
Normal file
@ -0,0 +1,200 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/display.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/XInput.h>
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
#ifdef KINC_EGL
|
||||
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
|
||||
#define MAXIMUM_WINDOWS 16
|
||||
#define MAXIMUM_DISPLAYS 16
|
||||
|
||||
struct kinc_x11_window {
|
||||
int display_index;
|
||||
int window_index;
|
||||
int width;
|
||||
int height;
|
||||
kinc_window_mode_t mode;
|
||||
Window window;
|
||||
XIM xInputMethod;
|
||||
XIC xInputContext;
|
||||
};
|
||||
|
||||
struct kinc_x11_display {
|
||||
int index;
|
||||
int current_mode;
|
||||
int num_modes;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
bool primary;
|
||||
char name[64];
|
||||
|
||||
RROutput output;
|
||||
RRCrtc crtc;
|
||||
};
|
||||
|
||||
struct kinc_x11_mouse {
|
||||
int current_window;
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct kinc_x11_atoms {
|
||||
Atom XdndAware;
|
||||
Atom XdndDrop;
|
||||
Atom XdndEnter;
|
||||
Atom XdndTextUriList;
|
||||
Atom XdndStatus;
|
||||
Atom XdndActionCopy;
|
||||
Atom XdndSelection;
|
||||
Atom CLIPBOARD;
|
||||
Atom UTF8_STRING;
|
||||
Atom XSEL_DATA;
|
||||
Atom TARGETS;
|
||||
Atom MULTIPLE;
|
||||
Atom TEXT_PLAIN;
|
||||
Atom WM_DELETE_WINDOW;
|
||||
Atom MOTIF_WM_HINTS;
|
||||
Atom NET_WM_NAME;
|
||||
Atom NET_WM_ICON_NAME;
|
||||
Atom NET_WM_STATE;
|
||||
Atom NET_WM_STATE_FULLSCREEN;
|
||||
|
||||
Atom MOUSE;
|
||||
Atom TABLET;
|
||||
Atom KEYBOARD;
|
||||
Atom TOUCHSCREEN;
|
||||
Atom TOUCHPAD;
|
||||
Atom BUTTONBOX;
|
||||
Atom BARCODE;
|
||||
Atom TRACKBALL;
|
||||
Atom QUADRATURE;
|
||||
Atom ID_MODULE;
|
||||
Atom ONE_KNOB;
|
||||
Atom NINE_KNOB;
|
||||
Atom KNOB_BOX;
|
||||
Atom SPACEBALL;
|
||||
Atom DATAGLOVE;
|
||||
Atom EYETRACKER;
|
||||
Atom CURSORKEYS;
|
||||
Atom FOOTMOUSE;
|
||||
Atom JOYSTICK;
|
||||
};
|
||||
|
||||
struct kinc_x11_libs {
|
||||
void *X11;
|
||||
void *Xcursor;
|
||||
void *Xi;
|
||||
void *Xinerama;
|
||||
void *Xrandr;
|
||||
};
|
||||
|
||||
struct kinc_x11_procs {
|
||||
Display *(*XOpenDisplay)(const char *name);
|
||||
Status (*XInternAtoms)(Display *display, char **names, int count, Bool only_if_exists, Atom *atoms_return);
|
||||
int (*XCloseDisplay)(Display *display);
|
||||
XErrorHandler (*XSetErrorHandler)(XErrorHandler handler);
|
||||
int (*XGetErrorText)(Display *, int, char *, int);
|
||||
int (*XPending)(Display *display);
|
||||
int (*XFlush)(Display *display);
|
||||
int (*XNextEvent)(Display *display, XEvent *event_return);
|
||||
int (*XPeekEvent)(Display *display, XEvent *event_return);
|
||||
int (*XRefreshKeyboardMapping)(XMappingEvent *event_map);
|
||||
int (*XwcLookupString)(XIC, XKeyPressedEvent *, wchar_t *, int, KeySym *, int *);
|
||||
int (*XFilterEvent)(XEvent *, Window);
|
||||
int (*XConvertSelection)(Display *, Atom, Atom, Atom, Window, Time);
|
||||
int (*XSetSelectionOwner)(Display *, Atom, Window, Time);
|
||||
int (*XLookupString)(XKeyEvent *, char *, int, KeySym *, XComposeStatus *);
|
||||
KeySym (*XkbKeycodeToKeysym)(Display *, KeyCode, int, int);
|
||||
int (*XSendEvent)(Display *, Window, int, long, XEvent *);
|
||||
int (*XGetWindowProperty)(Display *, Window, Atom, long, long, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
|
||||
int (*XFree)(void *);
|
||||
int (*XChangeProperty)(Display *, Window, Atom, Atom, int, int, const unsigned char *, int);
|
||||
int (*XDefineCursor)(Display *, Window, Cursor);
|
||||
int (*XUndefineCursor)(Display *, Window);
|
||||
Pixmap (*XCreateBitmapFromData)(Display *, Drawable, const char *, unsigned int, unsigned int);
|
||||
Cursor (*XCreatePixmapCursor)(Display *, Pixmap, Pixmap, XColor *, XColor *, unsigned int, unsigned int);
|
||||
int (*XFreePixmap)(Display *, Pixmap);
|
||||
Cursor (*XcursorLibraryLoadCursor)(Display *, const char *);
|
||||
int (*XWarpPointer)(Display *, Window, Window, int, int, unsigned int, unsigned int, int, int);
|
||||
int (*XQueryPointer)(Display *, Window, Window *, Window *, int *, int *, int *, int *, unsigned int *);
|
||||
Colormap (*XCreateColormap)(Display *, Window, Visual *, int);
|
||||
Window (*XCreateWindow)(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth,
|
||||
unsigned int class, Visual *visual, unsigned long valuemask, XSetWindowAttributes *attributes);
|
||||
int (*XMoveWindow)(Display *, Window, int, int);
|
||||
int (*XResizeWindow)(Display *, Window, unsigned int, unsigned int);
|
||||
int (*XDestroyWindow)(Display *, Window);
|
||||
int (*XSetClassHint)(Display *, Window, XClassHint *);
|
||||
char *(*XSetLocaleModifiers)(const char *);
|
||||
XIM (*XOpenIM)(Display *, struct _XrmHashBucketRec *, char *, char *);
|
||||
int (*XCloseIM)(XIM);
|
||||
XIC (*XCreateIC)(XIM, ...);
|
||||
void (*XDestroyIC)(XIC);
|
||||
void (*XSetICFocus)(XIC);
|
||||
int (*XMapWindow)(Display *, Window);
|
||||
int (*XUnmapWindow)(Display *, Window);
|
||||
int (*XSetWMProtocols)(Display *, Window, Atom *, int);
|
||||
|
||||
XDeviceInfo *(*XListInputDevices)(Display *, int *);
|
||||
void (*XFreeDeviceList)(XDeviceInfo *);
|
||||
XDevice *(*XOpenDevice)(Display *display, XID device_id);
|
||||
int (*XCloseDevice)(Display *display, XDevice *device);
|
||||
int (*XSelectExtensionEvent)(Display *, Window, XEventClass *, int);
|
||||
|
||||
int (*XineramaQueryExtension)(Display *dpy, int *event_base, int *error_base);
|
||||
int (*XineramaIsActive)(Display *dpy);
|
||||
XineramaScreenInfo *(*XineramaQueryScreens)(Display *dpy, int *number);
|
||||
|
||||
XRRScreenResources *(*XRRGetScreenResourcesCurrent)(Display *dpy, Window window);
|
||||
RROutput (*XRRGetOutputPrimary)(Display *dpy, Window window);
|
||||
XRROutputInfo *(*XRRGetOutputInfo)(Display *dpy, XRRScreenResources *resources, RROutput output);
|
||||
void (*XRRFreeOutputInfo)(XRROutputInfo *outputInfo);
|
||||
XRRCrtcInfo *(*XRRGetCrtcInfo)(Display *dpy, XRRScreenResources *resources, RRCrtc crtc);
|
||||
void (*XRRFreeCrtcInfo)(XRRCrtcInfo *crtcInfo);
|
||||
void (*XRRFreeScreenResources)(XRRScreenResources *resources);
|
||||
};
|
||||
|
||||
struct x11_pen_device {
|
||||
XID id;
|
||||
uint32_t motionEvent;
|
||||
XEventClass motionClass;
|
||||
uint32_t maxPressure;
|
||||
float current_pressure;
|
||||
|
||||
void (*press)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/);
|
||||
void (*move)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/);
|
||||
void (*release)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/);
|
||||
};
|
||||
|
||||
struct x11_context {
|
||||
Display *display;
|
||||
struct kinc_x11_libs libs;
|
||||
struct kinc_x11_atoms atoms;
|
||||
struct kinc_x11_mouse mouse;
|
||||
|
||||
struct x11_pen_device pen;
|
||||
struct x11_pen_device eraser;
|
||||
|
||||
int num_windows;
|
||||
struct kinc_x11_window windows[MAXIMUM_WINDOWS];
|
||||
int num_displays;
|
||||
struct kinc_x11_display displays[MAXIMUM_DISPLAYS];
|
||||
};
|
||||
|
||||
struct kinc_x11_procs xlib;
|
||||
struct x11_context x11_ctx;
|
||||
|
||||
void kinc_x11_copy_to_clipboard(const char *text);
|
Reference in New Issue
Block a user