35b8439b26
* working on windows * minor fix * working on macosx * Oops! I reversed resolution and frequency on macos * working on X11 * working on wayland * update the readme * format the readme Co-authored-by: Carlos Aragones <>
973 lines
32 KiB
C
973 lines
32 KiB
C
#include <MiniFB.h>
|
|
#include "MiniFB_internal.h"
|
|
#include "MiniFB_enums.h"
|
|
#include "WindowData.h"
|
|
#include "WindowData_Way.h"
|
|
|
|
#include <wayland-client.h>
|
|
#include <wayland-cursor.h>
|
|
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <linux/input.h>
|
|
#include <linux/input-event-codes.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
static void
|
|
destroy_window_data(SWindowData *window_data)
|
|
{
|
|
if(window_data == 0x0)
|
|
return;
|
|
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if(window_data_way != 0x0) {
|
|
mfb_timer_destroy(window_data_way->timer);
|
|
memset(window_data_way, 0, sizeof(SWindowData_Way));
|
|
free(window_data_way);
|
|
}
|
|
memset(window_data, 0, sizeof(SWindowData));
|
|
free(window_data);
|
|
}
|
|
|
|
static void
|
|
destroy(SWindowData *window_data)
|
|
{
|
|
if(window_data == 0x0)
|
|
return;
|
|
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if (window_data_way == 0x0 || window_data_way->display == 0x0) {
|
|
destroy_window_data(window_data);
|
|
return;
|
|
}
|
|
|
|
#define KILL(NAME) \
|
|
do \
|
|
{ \
|
|
if (window_data_way->NAME) \
|
|
wl_##NAME##_destroy(window_data_way->NAME); \
|
|
} while (0); \
|
|
window_data_way->NAME = 0x0;
|
|
|
|
KILL(shell_surface);
|
|
KILL(shell);
|
|
KILL(surface);
|
|
//KILL(buffer);
|
|
if(window_data_way->draw_buffer) {
|
|
wl_buffer_destroy(window_data_way->draw_buffer);
|
|
window_data_way->draw_buffer = 0x0;
|
|
}
|
|
KILL(shm_pool);
|
|
KILL(shm);
|
|
KILL(compositor);
|
|
KILL(keyboard);
|
|
KILL(seat);
|
|
KILL(registry);
|
|
#undef KILL
|
|
wl_display_disconnect(window_data_way->display);
|
|
|
|
destroy_window_data(window_data);
|
|
}
|
|
|
|
// This event provides a file descriptor to the client which can be memory-mapped
|
|
// to provide a keyboard mapping description.
|
|
// format: keymap format
|
|
// fd: keymap file descriptor
|
|
// size: keymap size, in bytes
|
|
static void
|
|
keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
|
|
{
|
|
kUnused(data);
|
|
kUnused(keyboard);
|
|
kUnused(format);
|
|
kUnused(fd);
|
|
kUnused(size);
|
|
}
|
|
|
|
// Notification that this seat's keyboard focus is on a certain surface.
|
|
// serial: serial number of the enter event
|
|
// surface: surface gaining keyboard focus
|
|
// keys: the currently pressed keys
|
|
static void
|
|
keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
|
|
{
|
|
kUnused(keyboard);
|
|
kUnused(serial);
|
|
kUnused(surface);
|
|
kUnused(keys);
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
window_data->is_active = true;
|
|
kCall(active_func, true);
|
|
}
|
|
|
|
// The leave notification is sent before the enter notification for the new focus.
|
|
// serial: serial number of the leave event
|
|
// surface: surface that lost keyboard focus
|
|
static void
|
|
keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
|
|
{
|
|
kUnused(keyboard);
|
|
kUnused(serial);
|
|
kUnused(surface);
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
window_data->is_active = false;
|
|
kCall(active_func, false);
|
|
}
|
|
|
|
// A key was pressed or released. The time argument is a timestamp with
|
|
// millisecond granularity, with an undefined base.
|
|
// serial: serial number of the key event
|
|
// time: timestamp with millisecond granularity
|
|
// key: key that produced the event
|
|
// state: physical state of the key
|
|
static void
|
|
keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
|
{
|
|
kUnused(keyboard);
|
|
kUnused(serial);
|
|
kUnused(time);
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
if(key < 512) {
|
|
mfb_key key_code = (mfb_key) g_keycodes[key];
|
|
bool is_pressed = (bool) (state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
switch (key_code)
|
|
{
|
|
case KB_KEY_LEFT_SHIFT:
|
|
case KB_KEY_RIGHT_SHIFT:
|
|
if(is_pressed)
|
|
window_data->mod_keys |= KB_MOD_SHIFT;
|
|
else
|
|
window_data->mod_keys &= ~KB_MOD_SHIFT;
|
|
break;
|
|
|
|
case KB_KEY_LEFT_CONTROL:
|
|
case KB_KEY_RIGHT_CONTROL:
|
|
if(is_pressed)
|
|
window_data->mod_keys |= KB_MOD_CONTROL;
|
|
else
|
|
window_data->mod_keys &= ~KB_MOD_CONTROL;
|
|
break;
|
|
|
|
case KB_KEY_LEFT_ALT:
|
|
case KB_KEY_RIGHT_ALT:
|
|
if(is_pressed)
|
|
window_data->mod_keys |= KB_MOD_ALT;
|
|
else
|
|
window_data->mod_keys &= ~KB_MOD_ALT;
|
|
break;
|
|
|
|
case KB_KEY_LEFT_SUPER:
|
|
case KB_KEY_RIGHT_SUPER:
|
|
if(is_pressed)
|
|
window_data->mod_keys |= KB_MOD_SUPER;
|
|
else
|
|
window_data->mod_keys &= ~KB_MOD_SUPER;
|
|
break;
|
|
}
|
|
|
|
window_data->key_status[key_code] = is_pressed;
|
|
kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed);
|
|
}
|
|
}
|
|
|
|
// Notifies clients that the modifier and/or group state has changed,
|
|
// and it should update its local state.
|
|
// serial: serial number of the modifiers event
|
|
// mods_depressed: depressed modifiers
|
|
// mods_latched: latched modifiers
|
|
// mods_locked: locked modifiers
|
|
// group: keyboard layout
|
|
static void
|
|
keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
|
{
|
|
kUnused(data);
|
|
kUnused(keyboard);
|
|
kUnused(serial);
|
|
kUnused(mods_depressed);
|
|
kUnused(mods_latched);
|
|
kUnused(mods_locked);
|
|
kUnused(group);
|
|
// it is not easy to identify them here :(
|
|
}
|
|
|
|
// Informs the client about the keyboard's repeat rate and delay.
|
|
// rate: the rate of repeating keys in characters per second
|
|
// delay: delay in milliseconds since key down until repeating starts
|
|
static void
|
|
keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
|
|
{
|
|
kUnused(data);
|
|
kUnused(keyboard);
|
|
kUnused(rate);
|
|
kUnused(delay);
|
|
}
|
|
|
|
static const struct
|
|
wl_keyboard_listener keyboard_listener = {
|
|
.keymap = keyboard_keymap,
|
|
.enter = keyboard_enter,
|
|
.leave = keyboard_leave,
|
|
.key = keyboard_key,
|
|
.modifiers = keyboard_modifiers,
|
|
.repeat_info = 0x0,
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Notification that this seat's pointer is focused on a certain surface.
|
|
//
|
|
// When a seat's focus enters a surface, the pointer image is
|
|
// undefined and a client should respond to this event by setting
|
|
// an appropriate pointer image with the set_cursor request.
|
|
//
|
|
// serial: serial number of the enter event
|
|
// surface: surface entered by the pointer
|
|
// sx: surface-local x coordinate
|
|
// sy: surface-local y coordinate
|
|
static void
|
|
pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
|
|
{
|
|
//kUnused(pointer);
|
|
//kUnused(serial);
|
|
kUnused(surface);
|
|
kUnused(sx);
|
|
kUnused(sy);
|
|
struct wl_buffer *buffer;
|
|
struct wl_cursor_image *image;
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
|
|
image = window_data_way->default_cursor->images[0];
|
|
buffer = wl_cursor_image_get_buffer(image);
|
|
|
|
wl_pointer_set_cursor(pointer, serial, window_data_way->cursor_surface, image->hotspot_x, image->hotspot_y);
|
|
wl_surface_attach(window_data_way->cursor_surface, buffer, 0, 0);
|
|
wl_surface_damage(window_data_way->cursor_surface, 0, 0, image->width, image->height);
|
|
wl_surface_commit(window_data_way->cursor_surface);
|
|
//fprintf(stderr, "Pointer entered surface %p at %d %d\n", surface, sx, sy);
|
|
}
|
|
|
|
// Notification that this seat's pointer is no longer focused on a certain surface.
|
|
//
|
|
// The leave notification is sent before the enter notification for the new focus.
|
|
//
|
|
// serial: serial number of the leave event
|
|
// surface: surface left by the pointer
|
|
static void
|
|
pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface)
|
|
{
|
|
kUnused(data);
|
|
kUnused(pointer);
|
|
kUnused(serial);
|
|
kUnused(surface);
|
|
|
|
//fprintf(stderr, "Pointer left surface %p\n", surface);
|
|
}
|
|
|
|
// Notification of pointer location change.
|
|
//
|
|
// The arguments sx and sy are the location relative to the focused surface.
|
|
//
|
|
// time: timestamp with millisecond granularity
|
|
// sx: surface-local x coordinate
|
|
// sy: surface-local y coordinate
|
|
static void
|
|
pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
|
|
{
|
|
kUnused(pointer);
|
|
kUnused(time);
|
|
|
|
//printf("Pointer moved at %f %f\n", sx / 256.0f, sy / 256.0f);
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
window_data->mouse_pos_x = sx >> 24;
|
|
window_data->mouse_pos_y = sy >> 24;
|
|
kCall(mouse_move_func, window_data->mouse_pos_x, window_data->mouse_pos_y);
|
|
}
|
|
|
|
// Mouse button click and release notifications.
|
|
//
|
|
// The location of the click is given by the last motion or enter
|
|
// event. The time argument is a timestamp with millisecond
|
|
// granularity, with an undefined base.
|
|
//
|
|
// The button is a button code as defined in the Linux kernel's
|
|
// linux/input-event-codes.h header file, e.g. BTN_LEFT.
|
|
//
|
|
// Any 16-bit button code value is reserved for future additions to
|
|
// the kernel's event code list. All other button codes above
|
|
// 0xFFFF are currently undefined but may be used in future
|
|
// versions of this protocol.
|
|
//
|
|
// serial: serial number of the button event
|
|
// time: timestamp with millisecond granularity
|
|
// button: button that produced the event
|
|
// state: physical state of the button
|
|
static void
|
|
pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
|
|
{
|
|
kUnused(pointer);
|
|
kUnused(serial);
|
|
kUnused(time);
|
|
|
|
//printf("Pointer button '%d'(%d)\n", button, state);
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
kCall(mouse_btn_func, (mfb_mouse_button) (button - BTN_MOUSE + 1), (mfb_key_mod) window_data->mod_keys, state == 1);
|
|
}
|
|
|
|
// Scroll and other axis notifications.
|
|
//
|
|
// For scroll events (vertical and horizontal scroll axes), the
|
|
// value parameter is the length of a vector along the specified
|
|
// axis in a coordinate space identical to those of motion events,
|
|
// representing a relative movement along the specified axis.
|
|
//
|
|
// For devices that support movements non-parallel to axes multiple
|
|
// axis events will be emitted.
|
|
//
|
|
// When applicable, for example for touch pads, the server can
|
|
// choose to emit scroll events where the motion vector is
|
|
// equivalent to a motion event vector.
|
|
//
|
|
// When applicable, a client can transform its content relative to
|
|
// the scroll distance.
|
|
//
|
|
// time: timestamp with millisecond granularity
|
|
// axis: axis type
|
|
// value: length of vector in surface-local coordinate space
|
|
static void
|
|
pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
{
|
|
kUnused(pointer);
|
|
kUnused(time);
|
|
kUnused(axis);
|
|
|
|
//printf("Pointer handle axis: axis: %d (0x%x)\n", axis, value);
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
if(axis == 0) {
|
|
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -(value / 256.0f));
|
|
}
|
|
else if(axis == 1) {
|
|
kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -(value / 256.0f), 0.0f);
|
|
}
|
|
}
|
|
|
|
static void
|
|
frame(void *data, struct wl_pointer *pointer) {
|
|
kUnused(data);
|
|
kUnused(pointer);
|
|
}
|
|
|
|
static void
|
|
axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source) {
|
|
kUnused(data);
|
|
kUnused(pointer);
|
|
kUnused(axis_source);
|
|
}
|
|
|
|
static void
|
|
axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis) {
|
|
kUnused(data);
|
|
kUnused(pointer);
|
|
kUnused(time);
|
|
kUnused(axis);
|
|
}
|
|
|
|
static void
|
|
axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete) {
|
|
kUnused(data);
|
|
kUnused(pointer);
|
|
kUnused(axis);
|
|
kUnused(discrete);
|
|
}
|
|
|
|
static const struct
|
|
wl_pointer_listener pointer_listener = {
|
|
.enter = pointer_enter,
|
|
.leave = pointer_leave,
|
|
.motion = pointer_motion,
|
|
.button = pointer_button,
|
|
.axis = pointer_axis,
|
|
.frame = 0x0,
|
|
.axis_source = 0x0,
|
|
.axis_stop = 0x0,
|
|
.axis_discrete = 0x0,
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
seat_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps)
|
|
{
|
|
kUnused(data);
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !window_data_way->keyboard)
|
|
{
|
|
window_data_way->keyboard = wl_seat_get_keyboard(seat);
|
|
wl_keyboard_add_listener(window_data_way->keyboard, &keyboard_listener, window_data);
|
|
}
|
|
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && window_data_way->keyboard)
|
|
{
|
|
wl_keyboard_destroy(window_data_way->keyboard);
|
|
window_data_way->keyboard = 0x0;
|
|
}
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !window_data_way->pointer)
|
|
{
|
|
window_data_way->pointer = wl_seat_get_pointer(seat);
|
|
wl_pointer_add_listener(window_data_way->pointer, &pointer_listener, window_data);
|
|
}
|
|
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && window_data_way->pointer)
|
|
{
|
|
wl_pointer_destroy(window_data_way->pointer);
|
|
window_data_way->pointer = 0x0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
seat_name(void *data, struct wl_seat *seat, const char *name) {
|
|
kUnused(data);
|
|
kUnused(seat);
|
|
printf("Seat '%s'n", name);
|
|
}
|
|
|
|
static const struct
|
|
wl_seat_listener seat_listener = {
|
|
.capabilities = seat_capabilities,
|
|
.name = 0x0,
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// pixel format description
|
|
//
|
|
// Informs the client about a valid pixel format that can be used
|
|
// for buffers. Known formats include argb8888 and xrgb8888.
|
|
//
|
|
// format: buffer pixel format
|
|
static void
|
|
shm_format(void *data, struct wl_shm *shm, uint32_t format)
|
|
{
|
|
kUnused(shm);
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if (window_data_way->shm_format == -1u)
|
|
{
|
|
switch (format)
|
|
{
|
|
// We could do RGBA, but that would not be what is expected from minifb...
|
|
// case WL_SHM_FORMAT_ARGB8888:
|
|
case WL_SHM_FORMAT_XRGB8888:
|
|
window_data_way->shm_format = format;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const struct
|
|
wl_shm_listener shm_listener = {
|
|
.format = shm_format
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
registry_global(void *data, struct wl_registry *registry, uint32_t id, char const *iface, uint32_t version)
|
|
{
|
|
kUnused(version);
|
|
|
|
SWindowData *window_data = (SWindowData *) data;
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if (strcmp(iface, "wl_compositor") == 0)
|
|
{
|
|
window_data_way->compositor = (struct wl_compositor *) wl_registry_bind(registry, id, &wl_compositor_interface, 1);
|
|
}
|
|
else if (strcmp(iface, "wl_shm") == 0)
|
|
{
|
|
window_data_way->shm = (struct wl_shm *) wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
|
if (window_data_way->shm) {
|
|
wl_shm_add_listener(window_data_way->shm, &shm_listener, window_data);
|
|
window_data_way->cursor_theme = wl_cursor_theme_load(0x0, 32, window_data_way->shm);
|
|
window_data_way->default_cursor = wl_cursor_theme_get_cursor(window_data_way->cursor_theme, "left_ptr");
|
|
}
|
|
}
|
|
else if (strcmp(iface, "wl_shell") == 0)
|
|
{
|
|
window_data_way->shell = (struct wl_shell *) wl_registry_bind(registry, id, &wl_shell_interface, 1);
|
|
}
|
|
else if (strcmp(iface, "wl_seat") == 0)
|
|
{
|
|
window_data_way->seat = (struct wl_seat *) wl_registry_bind(registry, id, &wl_seat_interface, 1);
|
|
if (window_data_way->seat)
|
|
{
|
|
wl_seat_add_listener(window_data_way->seat, &seat_listener, window_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
static const struct
|
|
wl_registry_listener registry_listener = {
|
|
.global = registry_global,
|
|
.global_remove = 0x0,
|
|
};
|
|
|
|
static void
|
|
handle_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial)
|
|
{
|
|
kUnused(data);
|
|
wl_shell_surface_pong(shell_surface, serial);
|
|
}
|
|
|
|
static void
|
|
handle_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height)
|
|
{
|
|
kUnused(data);
|
|
kUnused(shell_surface);
|
|
kUnused(edges);
|
|
kUnused(width);
|
|
kUnused(height);
|
|
}
|
|
|
|
static void
|
|
handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
|
|
{
|
|
kUnused(data);
|
|
kUnused(shell_surface);
|
|
}
|
|
|
|
static const struct wl_shell_surface_listener shell_surface_listener = {
|
|
handle_ping,
|
|
handle_configure,
|
|
handle_popup_done
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct mfb_window *
|
|
mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) {
|
|
// TODO: Not yet
|
|
kUnused(flags);
|
|
return mfb_open(title, width, height);
|
|
}
|
|
|
|
struct mfb_window *
|
|
mfb_open(const char *title, unsigned width, unsigned height)
|
|
{
|
|
int fd = -1;
|
|
|
|
SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData));
|
|
if(window_data == 0x0) {
|
|
return 0x0;
|
|
}
|
|
memset(window_data, 0, sizeof(SWindowData));
|
|
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) malloc(sizeof(SWindowData_Way));
|
|
if(window_data_way == 0x0) {
|
|
free(window_data);
|
|
return 0x0;
|
|
}
|
|
memset(window_data_way, 0, sizeof(SWindowData_Way));
|
|
window_data->specific = window_data_way;
|
|
|
|
window_data_way->shm_format = -1u;
|
|
|
|
window_data_way->display = wl_display_connect(0x0);
|
|
if (!window_data_way->display) {
|
|
free(window_data);
|
|
free(window_data_way);
|
|
return 0x0;
|
|
}
|
|
window_data_way->registry = wl_display_get_registry(window_data_way->display);
|
|
wl_registry_add_listener(window_data_way->registry, ®istry_listener, window_data);
|
|
|
|
init_keycodes();
|
|
|
|
if (wl_display_dispatch(window_data_way->display) == -1 ||
|
|
wl_display_roundtrip(window_data_way->display) == -1) {
|
|
return 0x0;
|
|
}
|
|
|
|
// did not get a format we want... meh
|
|
if (window_data_way->shm_format == -1u)
|
|
goto out;
|
|
if (!window_data_way->compositor)
|
|
goto out;
|
|
|
|
char const *xdg_rt_dir = getenv("XDG_RUNTIME_DIR");
|
|
char shmfile[PATH_MAX];
|
|
uint32_t ret = snprintf(shmfile, sizeof(shmfile), "%s/WaylandMiniFB-SHM-XXXXXX", xdg_rt_dir);
|
|
if (ret >= sizeof(shmfile))
|
|
goto out;
|
|
|
|
fd = mkstemp(shmfile);
|
|
if (fd == -1)
|
|
goto out;
|
|
unlink(shmfile);
|
|
|
|
uint32_t length = sizeof(uint32_t) * width * height;
|
|
|
|
if (ftruncate(fd, length) == -1)
|
|
goto out;
|
|
|
|
window_data_way->shm_ptr = (uint32_t *) mmap(0x0, length, PROT_WRITE, MAP_SHARED, fd, 0);
|
|
if (window_data_way->shm_ptr == MAP_FAILED)
|
|
goto out;
|
|
|
|
window_data->window_width = width;
|
|
window_data->window_height = height;
|
|
window_data->buffer_width = width;
|
|
window_data->buffer_height = height;
|
|
window_data->buffer_stride = width * sizeof(uint32_t);
|
|
window_data->dst_offset_x = 0;
|
|
window_data->dst_offset_y = 0;
|
|
window_data->dst_width = width;
|
|
window_data->dst_height = height;
|
|
|
|
window_data_way->shm_pool = wl_shm_create_pool(window_data_way->shm, fd, length);
|
|
window_data->draw_buffer = wl_shm_pool_create_buffer(window_data_way->shm_pool, 0,
|
|
window_data->buffer_width, window_data->buffer_height,
|
|
window_data->buffer_stride, window_data_way->shm_format);
|
|
|
|
close(fd);
|
|
fd = -1;
|
|
|
|
window_data_way->surface = wl_compositor_create_surface(window_data_way->compositor);
|
|
if (!window_data_way->surface)
|
|
goto out;
|
|
|
|
window_data_way->cursor_surface = wl_compositor_create_surface(window_data_way->compositor);
|
|
|
|
// There should always be a shell, right?
|
|
if (window_data_way->shell)
|
|
{
|
|
window_data_way->shell_surface = wl_shell_get_shell_surface(window_data_way->shell, window_data_way->surface);
|
|
if (!window_data_way->shell_surface)
|
|
goto out;
|
|
|
|
wl_shell_surface_set_title(window_data_way->shell_surface, title);
|
|
wl_shell_surface_add_listener(window_data_way->shell_surface, &shell_surface_listener, 0x0);
|
|
wl_shell_surface_set_toplevel(window_data_way->shell_surface);
|
|
}
|
|
|
|
wl_surface_attach(window_data_way->surface, (struct wl_buffer *) window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y);
|
|
wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height);
|
|
wl_surface_commit(window_data_way->surface);
|
|
|
|
window_data_way->timer = mfb_timer_create();
|
|
|
|
mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default);
|
|
|
|
printf("Window created using Wayland API\n");
|
|
|
|
return (struct mfb_window *) window_data;
|
|
|
|
out:
|
|
close(fd);
|
|
destroy(window_data);
|
|
return 0x0;
|
|
}
|
|
|
|
// done event
|
|
//
|
|
// Notify the client when the related request is done.
|
|
//
|
|
// callback_data: request-specific data for the callback
|
|
static void
|
|
frame_done(void *data, struct wl_callback *callback, uint32_t cookie)
|
|
{
|
|
kUnused(cookie);
|
|
wl_callback_destroy(callback);
|
|
|
|
*(uint32_t *)data = 1;
|
|
}
|
|
|
|
static const struct
|
|
wl_callback_listener frame_listener = {
|
|
.done = frame_done,
|
|
};
|
|
|
|
mfb_update_state
|
|
mfb_update(struct mfb_window *window, void *buffer)
|
|
{
|
|
uint32_t done = 0;
|
|
|
|
if(window == 0x0) {
|
|
return STATE_INVALID_WINDOW;
|
|
}
|
|
|
|
SWindowData *window_data = (SWindowData *) window;
|
|
if(window_data->close) {
|
|
destroy(window_data);
|
|
return STATE_EXIT;
|
|
}
|
|
|
|
if(buffer == 0x0) {
|
|
return STATE_INVALID_BUFFER;
|
|
}
|
|
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0)
|
|
return STATE_INTERNAL_ERROR;
|
|
|
|
// update shm buffer
|
|
memcpy(window_data_way->shm_ptr, buffer, window_data->buffer_stride * window_data->buffer_height);
|
|
|
|
wl_surface_attach(window_data_way->surface, (struct wl_buffer *) window_data->draw_buffer, window_data->dst_offset_x, window_data->dst_offset_y);
|
|
wl_surface_damage(window_data_way->surface, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height);
|
|
struct wl_callback *frame_callback = wl_surface_frame(window_data_way->surface);
|
|
if (!frame_callback) {
|
|
return STATE_INTERNAL_ERROR;
|
|
}
|
|
wl_callback_add_listener(frame_callback, &frame_listener, &done);
|
|
wl_surface_commit(window_data_way->surface);
|
|
|
|
while (!done && window_data->close == false) {
|
|
if (wl_display_dispatch(window_data_way->display) == -1 || wl_display_roundtrip(window_data_way->display) == -1) {
|
|
wl_callback_destroy(frame_callback);
|
|
return STATE_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
return STATE_OK;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
mfb_update_state
|
|
mfb_update_events(struct mfb_window *window)
|
|
{
|
|
if(window == 0x0) {
|
|
return STATE_INVALID_WINDOW;
|
|
}
|
|
|
|
SWindowData *window_data = (SWindowData *) window;
|
|
if(window_data->close) {
|
|
destroy(window_data);
|
|
return STATE_EXIT;
|
|
}
|
|
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
if (!window_data_way->display || wl_display_get_error(window_data_way->display) != 0)
|
|
return STATE_INTERNAL_ERROR;
|
|
|
|
if (wl_display_dispatch_pending(window_data_way->display) == -1) {
|
|
return STATE_INTERNAL_ERROR;
|
|
}
|
|
|
|
return STATE_OK;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
extern double g_time_for_frame;
|
|
|
|
bool
|
|
mfb_wait_sync(struct mfb_window *window) {
|
|
if(window == 0x0) {
|
|
return false;
|
|
}
|
|
|
|
SWindowData *window_data = (SWindowData *) window;
|
|
if(window_data->close) {
|
|
destroy(window_data);
|
|
return false;
|
|
}
|
|
|
|
SWindowData_Way *window_data_way = (SWindowData_Way *) window_data->specific;
|
|
double current;
|
|
uint32_t millis = 1;
|
|
while(1) {
|
|
if (wl_display_dispatch_pending(window_data_way->display) == -1) {
|
|
return false;
|
|
}
|
|
|
|
if(window_data->close) {
|
|
destroy_window_data(window_data);
|
|
return false;
|
|
}
|
|
|
|
current = mfb_timer_now(window_data_way->timer);
|
|
if (current >= g_time_for_frame) {
|
|
mfb_timer_reset(window_data_way->timer);
|
|
return true;
|
|
}
|
|
else if(current >= g_time_for_frame * 0.8) {
|
|
millis = 0;
|
|
}
|
|
|
|
usleep(millis * 1000);
|
|
//sched_yield();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
extern short int g_keycodes[512];
|
|
|
|
void
|
|
init_keycodes(void)
|
|
{
|
|
// Clear keys
|
|
for (size_t i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i)
|
|
g_keycodes[i] = 0;
|
|
|
|
g_keycodes[KEY_GRAVE] = KB_KEY_GRAVE_ACCENT;
|
|
g_keycodes[KEY_1] = KB_KEY_1;
|
|
g_keycodes[KEY_2] = KB_KEY_2;
|
|
g_keycodes[KEY_3] = KB_KEY_3;
|
|
g_keycodes[KEY_4] = KB_KEY_4;
|
|
g_keycodes[KEY_5] = KB_KEY_5;
|
|
g_keycodes[KEY_6] = KB_KEY_6;
|
|
g_keycodes[KEY_7] = KB_KEY_7;
|
|
g_keycodes[KEY_8] = KB_KEY_8;
|
|
g_keycodes[KEY_9] = KB_KEY_9;
|
|
g_keycodes[KEY_0] = KB_KEY_0;
|
|
g_keycodes[KEY_SPACE] = KB_KEY_SPACE;
|
|
g_keycodes[KEY_MINUS] = KB_KEY_MINUS;
|
|
g_keycodes[KEY_EQUAL] = KB_KEY_EQUAL;
|
|
g_keycodes[KEY_Q] = KB_KEY_Q;
|
|
g_keycodes[KEY_W] = KB_KEY_W;
|
|
g_keycodes[KEY_E] = KB_KEY_E;
|
|
g_keycodes[KEY_R] = KB_KEY_R;
|
|
g_keycodes[KEY_T] = KB_KEY_T;
|
|
g_keycodes[KEY_Y] = KB_KEY_Y;
|
|
g_keycodes[KEY_U] = KB_KEY_U;
|
|
g_keycodes[KEY_I] = KB_KEY_I;
|
|
g_keycodes[KEY_O] = KB_KEY_O;
|
|
g_keycodes[KEY_P] = KB_KEY_P;
|
|
g_keycodes[KEY_LEFTBRACE] = KB_KEY_LEFT_BRACKET;
|
|
g_keycodes[KEY_RIGHTBRACE] = KB_KEY_RIGHT_BRACKET;
|
|
g_keycodes[KEY_A] = KB_KEY_A;
|
|
g_keycodes[KEY_S] = KB_KEY_S;
|
|
g_keycodes[KEY_D] = KB_KEY_D;
|
|
g_keycodes[KEY_F] = KB_KEY_F;
|
|
g_keycodes[KEY_G] = KB_KEY_G;
|
|
g_keycodes[KEY_H] = KB_KEY_H;
|
|
g_keycodes[KEY_J] = KB_KEY_J;
|
|
g_keycodes[KEY_K] = KB_KEY_K;
|
|
g_keycodes[KEY_L] = KB_KEY_L;
|
|
g_keycodes[KEY_SEMICOLON] = KB_KEY_SEMICOLON;
|
|
g_keycodes[KEY_APOSTROPHE] = KB_KEY_APOSTROPHE;
|
|
g_keycodes[KEY_Z] = KB_KEY_Z;
|
|
g_keycodes[KEY_X] = KB_KEY_X;
|
|
g_keycodes[KEY_C] = KB_KEY_C;
|
|
g_keycodes[KEY_V] = KB_KEY_V;
|
|
g_keycodes[KEY_B] = KB_KEY_B;
|
|
g_keycodes[KEY_N] = KB_KEY_N;
|
|
g_keycodes[KEY_M] = KB_KEY_M;
|
|
g_keycodes[KEY_COMMA] = KB_KEY_COMMA;
|
|
g_keycodes[KEY_DOT] = KB_KEY_PERIOD;
|
|
g_keycodes[KEY_SLASH] = KB_KEY_SLASH;
|
|
g_keycodes[KEY_BACKSLASH] = KB_KEY_BACKSLASH;
|
|
g_keycodes[KEY_ESC] = KB_KEY_ESCAPE;
|
|
g_keycodes[KEY_TAB] = KB_KEY_TAB;
|
|
g_keycodes[KEY_LEFTSHIFT] = KB_KEY_LEFT_SHIFT;
|
|
g_keycodes[KEY_RIGHTSHIFT] = KB_KEY_RIGHT_SHIFT;
|
|
g_keycodes[KEY_LEFTCTRL] = KB_KEY_LEFT_CONTROL;
|
|
g_keycodes[KEY_RIGHTCTRL] = KB_KEY_RIGHT_CONTROL;
|
|
g_keycodes[KEY_LEFTALT] = KB_KEY_LEFT_ALT;
|
|
g_keycodes[KEY_RIGHTALT] = KB_KEY_RIGHT_ALT;
|
|
g_keycodes[KEY_LEFTMETA] = KB_KEY_LEFT_SUPER;
|
|
g_keycodes[KEY_RIGHTMETA] = KB_KEY_RIGHT_SUPER;
|
|
g_keycodes[KEY_MENU] = KB_KEY_MENU;
|
|
g_keycodes[KEY_NUMLOCK] = KB_KEY_NUM_LOCK;
|
|
g_keycodes[KEY_CAPSLOCK] = KB_KEY_CAPS_LOCK;
|
|
g_keycodes[KEY_PRINT] = KB_KEY_PRINT_SCREEN;
|
|
g_keycodes[KEY_SCROLLLOCK] = KB_KEY_SCROLL_LOCK;
|
|
g_keycodes[KEY_PAUSE] = KB_KEY_PAUSE;
|
|
g_keycodes[KEY_DELETE] = KB_KEY_DELETE;
|
|
g_keycodes[KEY_BACKSPACE] = KB_KEY_BACKSPACE;
|
|
g_keycodes[KEY_ENTER] = KB_KEY_ENTER;
|
|
g_keycodes[KEY_HOME] = KB_KEY_HOME;
|
|
g_keycodes[KEY_END] = KB_KEY_END;
|
|
g_keycodes[KEY_PAGEUP] = KB_KEY_PAGE_UP;
|
|
g_keycodes[KEY_PAGEDOWN] = KB_KEY_PAGE_DOWN;
|
|
g_keycodes[KEY_INSERT] = KB_KEY_INSERT;
|
|
g_keycodes[KEY_LEFT] = KB_KEY_LEFT;
|
|
g_keycodes[KEY_RIGHT] = KB_KEY_RIGHT;
|
|
g_keycodes[KEY_DOWN] = KB_KEY_DOWN;
|
|
g_keycodes[KEY_UP] = KB_KEY_UP;
|
|
g_keycodes[KEY_F1] = KB_KEY_F1;
|
|
g_keycodes[KEY_F2] = KB_KEY_F2;
|
|
g_keycodes[KEY_F3] = KB_KEY_F3;
|
|
g_keycodes[KEY_F4] = KB_KEY_F4;
|
|
g_keycodes[KEY_F5] = KB_KEY_F5;
|
|
g_keycodes[KEY_F6] = KB_KEY_F6;
|
|
g_keycodes[KEY_F7] = KB_KEY_F7;
|
|
g_keycodes[KEY_F8] = KB_KEY_F8;
|
|
g_keycodes[KEY_F9] = KB_KEY_F9;
|
|
g_keycodes[KEY_F10] = KB_KEY_F10;
|
|
g_keycodes[KEY_F11] = KB_KEY_F11;
|
|
g_keycodes[KEY_F12] = KB_KEY_F12;
|
|
g_keycodes[KEY_F13] = KB_KEY_F13;
|
|
g_keycodes[KEY_F14] = KB_KEY_F14;
|
|
g_keycodes[KEY_F15] = KB_KEY_F15;
|
|
g_keycodes[KEY_F16] = KB_KEY_F16;
|
|
g_keycodes[KEY_F17] = KB_KEY_F17;
|
|
g_keycodes[KEY_F18] = KB_KEY_F18;
|
|
g_keycodes[KEY_F19] = KB_KEY_F19;
|
|
g_keycodes[KEY_F20] = KB_KEY_F20;
|
|
g_keycodes[KEY_F21] = KB_KEY_F21;
|
|
g_keycodes[KEY_F22] = KB_KEY_F22;
|
|
g_keycodes[KEY_F23] = KB_KEY_F23;
|
|
g_keycodes[KEY_F24] = KB_KEY_F24;
|
|
g_keycodes[KEY_KPSLASH] = KB_KEY_KP_DIVIDE;
|
|
g_keycodes[KEY_KPDOT] = KB_KEY_KP_MULTIPLY;
|
|
g_keycodes[KEY_KPMINUS] = KB_KEY_KP_SUBTRACT;
|
|
g_keycodes[KEY_KPPLUS] = KB_KEY_KP_ADD;
|
|
g_keycodes[KEY_KP0] = KB_KEY_KP_0;
|
|
g_keycodes[KEY_KP1] = KB_KEY_KP_1;
|
|
g_keycodes[KEY_KP2] = KB_KEY_KP_2;
|
|
g_keycodes[KEY_KP3] = KB_KEY_KP_3;
|
|
g_keycodes[KEY_KP4] = KB_KEY_KP_4;
|
|
g_keycodes[KEY_KP5] = KB_KEY_KP_5;
|
|
g_keycodes[KEY_KP6] = KB_KEY_KP_6;
|
|
g_keycodes[KEY_KP7] = KB_KEY_KP_7;
|
|
g_keycodes[KEY_KP8] = KB_KEY_KP_8;
|
|
g_keycodes[KEY_KP9] = KB_KEY_KP_9;
|
|
g_keycodes[KEY_KPCOMMA] = KB_KEY_KP_DECIMAL;
|
|
g_keycodes[KEY_KPEQUAL] = KB_KEY_KP_EQUAL;
|
|
g_keycodes[KEY_KPENTER] = KB_KEY_KP_ENTER;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool
|
|
mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) {
|
|
|
|
SWindowData *window_data = (SWindowData *) window;
|
|
|
|
if(offset_x + width > window_data->window_width) {
|
|
return false;
|
|
}
|
|
if(offset_y + height > window_data->window_height) {
|
|
return false;
|
|
}
|
|
|
|
// TODO: Not yet
|
|
// window_data->dst_offset_x = offset_x;
|
|
// window_data->dst_offset_y = offset_y;
|
|
// window_data->dst_width = width;
|
|
// window_data->dst_height = height;
|
|
|
|
return false;
|
|
}
|
|
|