Compare commits

...
Sign in to create a new pull request.

19 commits

Author SHA1 Message Date
82319aa616 h 2025-12-05 17:58:44 -07:00
495ea93c74 working pixmap 2025-12-05 15:18:21 -07:00
0fc8b09913 wayland resize 2025-12-05 14:50:04 -07:00
39f44a56e3 fixed new kde bug where decorations were null 2025-12-05 12:40:44 -07:00
247e0b361c introduce MwLLEndDraw, which can be stubbed safely on any platforms and exists purely for wayland to be able to swap buffers at a better time 2025-12-03 23:00:40 -07:00
a932fc00ea opengl complete 2025-12-03 22:26:03 -07:00
0adc98a2a2 wayland: give up on cairo and switch to OpenGL 2025-12-03 18:17:27 -07:00
c50e920123 cairo about to make me give up on the wayland port 2025-12-02 23:42:55 -07:00
8cbde42de3 have cairo fill in lines idk 2025-12-01 20:45:21 -07:00
be2eb6483c throw in the towel and switch to cairo lmao 2025-12-01 20:05:03 -07:00
749be3762b Merge branch 'master' into wayland 2025-12-01 19:20:17 -07:00
82626cab22 merge 2025-12-01 19:18:43 -07:00
67df6592e7 Merge branch 'IoI_xD-wayland' 2025-12-01 19:16:41 -07:00
37fe636c75 more wayland work 2025-12-01 19:12:49 -07:00
5ad21381c5 more wayland impls 2025-12-01 14:19:07 -07:00
b2ea14c354 handle resizing, turn _MwLLWaylandToplevel into a pointer 2025-12-01 11:45:55 -07:00
43b0b86a0f changed my mind, removing wl_shell stuff makes the resulting library smaller and i don't actually feel like supporting a feature that's been obsolete since 2013 2025-11-29 21:04:01 -07:00
5a9a33e873 wayland: we now have subsurfaces working 2025-11-29 20:52:56 -07:00
843cc74c4c wayland backend init commit 2025-11-29 17:56:33 -07:00
18 changed files with 1170 additions and 32 deletions

8
.gitignore vendored
View file

@ -4,8 +4,8 @@
examples/* examples/*
examples/*.exe examples/*.exe
examples/*/* examples/*/*
examples/*/*.exe !examples/*/*.c
!examples/*/ !examples/*/*.spv
!examples/*.*
!examples/*/*.*
compile_flags.txt compile_flags.txt
*.a
Makefile

View file

@ -56,13 +56,13 @@ void resize(MwWidget w, void* user, void* client) {
int main() { int main() {
MwWidget window; MwWidget window;
int i; int i;
MwLibraryInit(); MwLibraryInit();
window = MwVaCreateWidget(MwWindowClass, "window", NULL, MwDEFAULT, MwDEFAULT, (ww = 500), (wh = 500), window = MwVaCreateWidget(MwWindowClass, "window", NULL, MwDEFAULT, MwDEFAULT, (ww = 500), (wh = 500),
MwNtitle, "rotate", MwNtitle, "rotate",
NULL); NULL);
for(i = 0; i < (int)(sizeof(buttons) / sizeof(buttons[0])); i++) { for(i = 0; i < (int)(sizeof(buttons) / sizeof(buttons[0])); i++) {
const char* color = ""; const char* color = "";

View file

@ -128,7 +128,7 @@ MWDECL void MwLoop(MwWidget handle);
*/ */
MWDECL int MwStep(MwWidget handle); MWDECL int MwStep(MwWidget handle);
/*! /*!MwStep(
* @brief Check if any event is pending * @brief Check if any event is pending
* @param handle Widget * @param handle Widget
* @return `1` if any event is pending * @return `1` if any event is pending

View file

@ -26,13 +26,15 @@ typedef void* MwLLPixmap;
enum MwLLBackends { enum MwLLBackends {
MwLLBackendX11 = 0, MwLLBackendX11 = 0,
MwLLBackendGDI MwLLBackendGDI,
MwLLBackendWayland,
}; };
struct _MwLLCommon { struct _MwLLCommon {
void* user; void* user;
int copy_buffer; int copy_buffer;
int type; int type;
int success;
MwLLHandler handler; MwLLHandler handler;
}; };
@ -56,6 +58,9 @@ struct _MwLLCommonPixmap {
#ifdef USE_GDI #ifdef USE_GDI
#include <Mw/LowLevel/GDI.h> #include <Mw/LowLevel/GDI.h>
#endif #endif
#ifdef USE_WAYLAND
#include <Mw/LowLevel/Wayland.h>
#endif
union _MwLL { union _MwLL {
struct _MwLLCommon common; struct _MwLLCommon common;
@ -65,6 +70,9 @@ union _MwLL {
#ifdef USE_GDI #ifdef USE_GDI
struct _MwLLGDI gdi; struct _MwLLGDI gdi;
#endif #endif
#ifdef USE_WAYLAND
struct _MwLLWayland wayland;
#endif
}; };
union _MwLLColor { union _MwLLColor {
@ -75,6 +83,9 @@ union _MwLLColor {
#ifdef USE_GDI #ifdef USE_GDI
struct _MwLLGDIColor gdi; struct _MwLLGDIColor gdi;
#endif #endif
#ifdef USE_WAYLAND
struct _MwLLWaylandColor wayland;
#endif
}; };
union _MwLLPixmap { union _MwLLPixmap {
@ -85,6 +96,9 @@ union _MwLLPixmap {
#ifdef USE_GDI #ifdef USE_GDI
struct _MwLLGDIPixmap gdi; struct _MwLLGDIPixmap gdi;
#endif #endif
#ifdef USE_WAYLAND
struct _MwLLWaylandPixmap wayland;
#endif
}; };
#endif #endif
#include <Mw/TypeDefs.h> #include <Mw/TypeDefs.h>
@ -150,6 +164,7 @@ MWDECL void (*MwLLDestroy)(MwLL handle);
MWDECL void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); MWDECL void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color);
MWDECL void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); MWDECL void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color);
MWDECL void (*MwLLEndDraw)(MwLL handle);
MWDECL MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); MWDECL MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b);
MWDECL void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); MWDECL void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b);
@ -184,8 +199,6 @@ MWDECL void (*MwLLMakePopup)(MwLL handle, MwLL parent);
MWDECL void (*MwLLBeginStateChange)(MwLL handle); MWDECL void (*MwLLBeginStateChange)(MwLL handle);
MWDECL void (*MwLLEndStateChange)(MwLL handle); MWDECL void (*MwLLEndStateChange)(MwLL handle);
MWDECL void (*MwLLSetBackground)(MwLL handle, MwLLColor color);
MWDECL void (*MwLLFocus)(MwLL handle); MWDECL void (*MwLLFocus)(MwLL handle);
MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle);

View file

@ -0,0 +1,110 @@
/* $Id$ */
/*!
* @file Mw/LowLevel/Wayland.h
* @brief Wayland Backend
* @warning This is used internally
*/
#ifndef __MW_LOWLEVEL_WAYLAND_H__
#define __MW_LOWLEVEL_WAYLAND_H__
#include "Mw/BaseTypes.h"
#include <Mw/MachDep.h>
#include <Mw/TypeDefs.h>
#include <Mw/LowLevel.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
MWDECL int MwLLWaylandCallInit(void);
#ifndef WL_PROTOCOLS_DEFINED
#define WL_PROTOCOLS_DEFINED
#include "Wayland/xdg-shell-client-protocol.h"
#include "Wayland/xdg-decoration-client-protocol.h"
#include "Wayland/cursor-shape-client-protocol.h"
#endif
typedef struct wayland_protocol {
void* listener;
void* context;
} wayland_protocol_t;
typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*);
struct _MwLLWaylandTopLevel {
struct xdg_surface* xdg_surface;
struct xdg_toplevel* xdg_top_level;
struct xdg_toplevel_listener xdg_toplevel_listener;
struct xdg_surface_listener xdg_surface_listener;
struct xkb_context* xkb_context;
MwBool running;
MwBool compositor_created;
MwBool xdg_wm_base_created;
MwBool xdg_surface_created;
};
struct _MwLLWayland {
struct _MwLLCommon common;
union {
struct _MwLLWaylandTopLevel* toplevel;
struct wl_subsurface* subsurface;
};
enum {
MWLL_WAYLAND_TOPLEVEL = 0,
MWLL_WAYLAND_SUBSURFACE = 1,
} type;
struct {
const char* key;
wl_setup_func* value;
}* wl_protocol_setup_map;
struct {
const char* key;
wayland_protocol_t* value;
}* wl_protocol_map;
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor;
struct wl_surface* surface;
struct wl_shm* shm;
struct wl_registry_listener registry_listener;
MwBool configured;
MwBool force_redraw;
MwBool egl_setup;
MwBool egl_do_resetup;
MwU32 x, y, ww, wh;
int z_index;
MwLL parent;
GLuint fbo;
unsigned int fbo_texture;
EGLNativeWindowType egl_window_native;
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
EGLConfig egl_config;
};
struct _MwLLWaylandColor {
struct _MwLLCommonColor common;
};
struct _MwLLWaylandPixmap {
struct _MwLLCommonPixmap common;
GLuint texture;
};
#endif

View file

@ -0,0 +1 @@
*protocol.h

View file

@ -0,0 +1 @@
Folder for wayland-scanner to place any of its files.

View file

@ -1,4 +1,9 @@
# $Id$ # $Id$
use_backend("x11");
if(system("wayland-scanner -v >/dev/null 2>&1") == 0){
use_backend("wayland", "x11");
} else {
use_backend("x11");
}
1; 1;

View file

@ -27,6 +27,19 @@ if (grep(/^gdi$/, @backends)) {
$gl_libs = "-lopengl32 -lglu32"; $gl_libs = "-lopengl32 -lglu32";
} }
if (grep(/^wayland$/, @backends)) {
add_cflags("-DUSE_WAYLAND");
new_object("src/backend/wayland.c");
add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon");
scan_wayland_protocol("stable", "xdg-shell","");
scan_wayland_protocol("stable", "tablet","-v2");
scan_wayland_protocol("staging", "cursor-shape","-v1");
scan_wayland_protocol("unstable", "xdg-decoration","-unstable-v1");
$gl_libs = "-lGL -lGLU";
}
if (param_get("stb-image")) { if (param_get("stb-image")) {
add_cflags("-DUSE_STB_IMAGE"); add_cflags("-DUSE_STB_IMAGE");
} }

View file

@ -55,6 +55,23 @@ sub use_backend {
} }
} }
sub scan_wayland_protocol {
my $tier = $_[0];
my $proto = $_[1];
my $ver = $_[2];
my $proto_c = "src/backend/wayland-${proto}-protocol.c";
if(system("wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c}") != 0) {
print("^ Error on getting private code for /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml\n");
} else {
new_object($proto_c);
};
if(system("wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml include/Mw/LowLevel/Wayland/${proto}-client-protocol.h")) {
print("^ Error on getting client header for /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml\n");
};
}
our %params = (); our %params = ();
sub param_set { sub param_set {

1
src/backend/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
wayland*protocol.c

View file

@ -11,6 +11,7 @@
\ \
MwLLPolygon = MwLLPolygonImpl; \ MwLLPolygon = MwLLPolygonImpl; \
MwLLLine = MwLLLineImpl; \ MwLLLine = MwLLLineImpl; \
MwLLEndDraw = MwLLEndDrawImpl; \
\ \
MwLLAllocColor = MwLLAllocColorImpl; \ MwLLAllocColor = MwLLAllocColorImpl; \
MwLLColorUpdate = MwLLColorUpdateImpl; \ MwLLColorUpdate = MwLLColorUpdateImpl; \
@ -44,8 +45,6 @@
\ \
MwLLBeginStateChange = MwLLBeginStateChangeImpl; \ MwLLBeginStateChange = MwLLBeginStateChangeImpl; \
MwLLEndStateChange = MwLLEndStateChangeImpl; \ MwLLEndStateChange = MwLLEndStateChangeImpl; \
\
MwLLSetBackground = MwLLSetBackgroundImpl; \
\ \
MwLLFocus = MwLLFocusImpl; \ MwLLFocus = MwLLFocusImpl; \
MwLLGrabPointer = MwLLGrabPointerImpl; \ MwLLGrabPointer = MwLLGrabPointerImpl; \

View file

@ -278,6 +278,8 @@ static void MwLLDestroyImpl(MwLL handle) {
free(handle); free(handle);
} }
static void MwLLEndDrawImpl(MwLL handle) {}
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
POINT* p = malloc(sizeof(*p) * points_count); POINT* p = malloc(sizeof(*p) * points_count);
HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0)); HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
@ -342,11 +344,6 @@ static void MwLLFreeColorImpl(MwLLColor color) {
free(color); free(color);
} }
static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) {
(void)handle;
(void)color;
}
static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) {
RECT rc; RECT rc;

970
src/backend/wayland.c Normal file
View file

@ -0,0 +1,970 @@
/* $Id$ */
// #include <GL/gl.h>
#include <GL/gl.h>
#include <Mw/Milsko.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include "../../external/stb_ds.h"
#include "Mw/BaseTypes.h"
#include "Mw/LowLevel.h"
#include <sys/mman.h>
#include <wayland-egl-core.h>
#include <wayland-util.h>
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus;
#define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name)
static void new_protocol(void* data, struct wl_registry* registry,
MwU32 name, const char* interface,
MwU32 version) {
struct _MwLLWayland* wayland = data;
wl_setup_func* func = shget(wayland->wl_protocol_setup_map, interface);
if(func != NULL) {
// printf("registering interface %s\n", interface);
shput(wayland->wl_protocol_map, interface, func(name, data));
} else {
// printf("unknown interface %s\n", interface);
}
};
static void protocol_removed(void* data,
struct wl_registry* registry,
MwU32 name) {
};
static void wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {};
static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat,
MwU32 capabilities) {};
void xdg_wm_base_ping(void* data,
struct xdg_wm_base* xdg_wm_base,
MwU32 serial) {
// The compositor will send us a ping event to check that we're responsive.
// We need to send back a pong request immediately.
xdg_wm_base_pong(xdg_wm_base, serial);
};
static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
proto->listener = malloc(sizeof(struct wl_seat_listener));
((struct wl_seat_listener*)proto->listener)->name = wl_seat_name;
((struct wl_seat_listener*)proto->listener)->capabilities = wl_seat_capabilities;
proto->context = wl_registry_bind(wayland->registry, name, &wl_seat_interface, 1);
wl_seat_add_listener(proto->context, proto->listener, wayland);
return proto;
}
static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1);
return NULL;
}
static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1);
return NULL;
}
static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
proto->listener = malloc(sizeof(struct xdg_wm_base_listener));
((struct xdg_wm_base_listener*)proto->listener)->ping = xdg_wm_base_ping;
proto->context = wl_registry_bind(wayland->registry, name, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(proto->context, proto->listener, wayland);
return proto;
}
static wayland_protocol_t* wp_cursor_shape_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
proto->listener = NULL;
proto->context = wl_registry_bind(wayland->registry, name, &wp_cursor_shape_manager_v1_interface, 1);
return proto;
}
typedef struct zxdg_decoration_manager_v1_context {
struct zxdg_decoration_manager_v1* manager;
// struct zxdg_decoration_toplevel_v1* toplevel;
struct zxdg_toplevel_decoration_v1* decoration;
} zxdg_decoration_manager_v1_context_t;
static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
zxdg_decoration_manager_v1_context_t* ctx = malloc(sizeof(zxdg_decoration_manager_v1_context_t));
proto->listener = NULL;
ctx->manager = wl_registry_bind(wayland->registry, name, &zxdg_decoration_manager_v1_interface, 1);
;
proto->context = ctx;
return proto;
}
static MwBool egl_setup(MwLL self, int width, int height) {
int err;
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLContext context;
EGLSurface surface;
EGLint fbAttribs[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE};
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 1,
EGL_CONTEXT_MAJOR_VERSION, 1,
EGL_CONTEXT_MINOR_VERSION, 1,
EGL_NONE};
EGLDisplay display = eglGetDisplay(self->wayland.display);
if(display == EGL_NO_DISPLAY) {
printf("ERROR: eglGetDisplay, %0X\n", eglGetError());
return MwFALSE;
}
// Initialize EGL
if(!eglInitialize(display, &majorVersion, &minorVersion)) {
printf("ERROR: eglInitialize, %0X\n", eglGetError());
return MwFALSE;
}
// Get configs
if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || (numConfigs == 0)) {
printf("ERROR: eglGetConfigs, %0X\n", eglGetError());
return MwFALSE;
}
// Choose config
if((eglChooseConfig(display, fbAttribs, &self->wayland.egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) {
printf("ERROR: eglChooseConfig, %0X\n", eglGetError());
return MwFALSE;
}
self->wayland.egl_window_native =
wl_egl_window_create(self->wayland.surface, width, height);
if(self->wayland.egl_window_native == EGL_NO_SURFACE) {
printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n");
return MwFALSE;
}
// Create a surface
surface = eglCreateWindowSurface(display, self->wayland.egl_config, self->wayland.egl_window_native, NULL);
if(surface == EGL_NO_SURFACE) {
printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError());
return MwFALSE;
}
eglBindAPI(EGL_OPENGL_API);
// Create a GL context
context = eglCreateContext(display, self->wayland.egl_config, EGL_NO_CONTEXT, contextAttribs);
if(context == EGL_NO_CONTEXT) {
printf("ERROR: eglCreateContext, %0X\n", eglGetError());
return MwFALSE;
}
// Make the context current
if(!eglMakeCurrent(display, surface, surface, context)) {
printf("ERROR: eglMakeCurrent, %0X\n", eglGetError());
return MwFALSE;
}
glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)eglGetProcAddress("glGenFramebuffers");
glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D");
glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)eglGetProcAddress("glGenRenderbuffers");
// glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)eglGetProcAddress("glRenderbufferStorage");
glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)eglGetProcAddress("glFramebufferRenderbuffer");
glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)eglGetProcAddress("glBindRenderbuffer");
glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)eglGetProcAddress("glBindFramebuffer");
glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)eglGetProcAddress("glCheckFramebufferStatus");
glGenTextures(1, &self->wayland.fbo_texture);
glBindTexture(GL_TEXTURE_2D, self->wayland.fbo_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &self->wayland.fbo);
glBindFramebuffer(GL_FRAMEBUFFER_BINDING, self->wayland.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->wayland.fbo_texture, 0);
if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
printf("Error binding framebuffer: %0X\n", err);
return MwFALSE;
}
glBindFramebuffer(GL_FRAMEBUFFER_BINDING, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, -1, 1);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
self->wayland.egl_display = display;
self->wayland.egl_surface = surface;
self->wayland.egl_context = context;
printf("EGL success\n");
return MwTRUE;
}
static void egl_resetup(MwLL handle) {
int err;
if(!handle->wayland.egl_do_resetup) {
return;
}
if(!eglMakeCurrent(handle->wayland.egl_display, 0, 0, handle->wayland.egl_context)) {
printf("ERROR: eglMakeCurrent, %0X\n", eglGetError());
return;
}
if(!eglDestroySurface(handle->wayland.egl_display, handle->wayland.egl_surface)) {
printf("ERROR: eglDestroySurface, %0X\n", eglGetError());
return;
};
handle->wayland.egl_surface = eglCreateWindowSurface(handle->wayland.egl_display, handle->wayland.egl_config, handle->wayland.egl_window_native, NULL);
if(handle->wayland.egl_surface == EGL_NO_SURFACE) {
printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError());
return;
}
if(!eglMakeCurrent(handle->wayland.egl_display, handle->wayland.egl_surface, handle->wayland.egl_surface, handle->wayland.egl_context)) {
printf("ERROR: eglMakeCurrent, %0X\n", eglGetError());
return;
}
glDeleteTextures(1, &handle->wayland.fbo_texture);
glGenTextures(1, &handle->wayland.fbo_texture);
glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, handle->wayland.ww, handle->wayland.wh, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &handle->wayland.fbo);
glBindFramebuffer(GL_FRAMEBUFFER_BINDING, handle->wayland.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0);
if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
printf("Error binding framebuffer: %0X\n", err);
return;
}
glBindFramebuffer(GL_FRAMEBUFFER_BINDING, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, handle->wayland.ww, handle->wayland.wh, 0, -1, 1);
glViewport(0, 0, handle->wayland.ww, handle->wayland.wh);
handle->wayland.egl_do_resetup = MwFALSE;
}
static void xdg_toplevel_configure(void* data,
struct xdg_toplevel* xdg_toplevel,
MwI32 width, MwI32 height,
struct wl_array* states) {
MwLL self = data;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D");
if(width == 0 || height == 0) {
width = self->wayland.ww;
height = self->wayland.wh;
// if it's still 0 then bail
if(width == 0 || height == 0) {
return;
}
}
self->wayland.ww = width;
self->wayland.wh = height;
xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh);
MwLLSetWH(self, width, height);
MwLLDispatch(self, resize, NULL);
if(!self->wayland.egl_setup) {
self->wayland.egl_setup = egl_setup(self, width, height);
MwLLForceRender(self);
}
wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0);
self->wayland.egl_do_resetup = MwTRUE;
egl_resetup(self);
return;
};
static void decoration_configure(
void* data, struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1,
MwU32 mode) {
}
static void xdg_toplevel_close(
void* data, struct xdg_toplevel* xdg_toplevel) {
MwLL self = data;
// Stop running if the user requests to close the toplevel
self->wayland.toplevel->running = MwFALSE;
};
static void xdg_surface_configure(
void* data, struct xdg_surface* xdg_surface, MwU32 serial) {
MwLL self = data;
// The compositor configures our surface, acknowledge the configure event
xdg_surface_ack_configure(xdg_surface, serial);
if(self->wayland.configured) {
// If this isn't the first configure event we've received, we already
// have a buffer attached, so no need to do anything. Commit the
// surface to apply the configure acknowledgement.
// wl_surface_attach(self->surface, self->buffer, 0, 0);
wl_surface_commit(self->wayland.surface);
}
self->wayland.configured = MwTRUE;
}
static int event_loop(MwLL handle) {
enum {
DISPLAY_FD,
KEYREPEAT_FD,
CURSOR_FD
};
struct pollfd fd;
int timeout = 100;
struct _MwLLWayland* wayland = &handle->wayland;
if(wayland->display == NULL) {
return 0;
}
fd.fd = wl_display_get_fd(wayland->display);
fd.events = POLLIN;
/* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */
while(wl_display_flush(wayland->display) == -1) {
if(errno != EAGAIN) {
return MwFALSE;
}
while(poll(&fd, 1, -1) == -1) {
if(errno != EINTR && errno != EAGAIN) {
wl_display_cancel_read(wayland->display);
wayland->toplevel->running = MwFALSE;
return 0;
}
}
}
/*
IOI:
I took this from ioilib which I in turn adapted from SDL. I think this is meant to be required?
But doing this on my main machine causes the decorations manager to be null...? This doesn't show up on the project currently using ioilib.
Race condition? Random KDE bug? Who knows, but it seems that not polling for this works anyways (possibly because we already flush events above and then cancel reads when we actually need to close).
*/
/*
// Condition where no events are being sent.
if(!poll(&fd, 1, timeout)) {
wl_display_cancel_read(wayland->display);
// In this case, we need to commit the surface for any animations, etc.
wl_surface_commit(wayland->surface);
return 0;
}
*/
if(fd.revents & POLLIN) {
wl_display_read_events(wayland->display);
if(wl_display_dispatch_pending(wayland->display) > 0) {
}
} else {
if(wl_display_dispatch_pending(wayland->display) == 0) {
MwLLDispatch(handle, draw, NULL);
}
}
return 0;
}
#define WL_INTERFACE(interface) \
shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup);
static void setup_callbacks(struct _MwLLWayland* wayland) {
wayland->registry_listener.global = new_protocol;
wayland->registry_listener.global_remove = protocol_removed;
wayland->wl_protocol_setup_map = NULL;
wayland->wl_protocol_map = NULL;
WL_INTERFACE(wl_compositor);
WL_INTERFACE(wl_subcompositor);
if(wayland->type == MWLL_WAYLAND_TOPLEVEL) {
WL_INTERFACE(wl_seat);
WL_INTERFACE(xdg_wm_base);
WL_INTERFACE(zxdg_decoration_manager_v1);
WL_INTERFACE(wp_cursor_shape_manager_v1);
}
}
#undef WL_INTERFACE
static void setup_toplevel(MwLL r, int x, int y) {
int i;
struct wl_region* region;
r->wayland.type = MWLL_WAYLAND_TOPLEVEL;
r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel));
setup_callbacks(&r->wayland);
// Connect to the Wayland compositor
r->wayland.display = wl_display_connect(NULL);
if(r->wayland.display == NULL) {
printf("wayland: failed to create display\n");
r->common.success = MwFALSE;
return;
}
// Do a roundtrip to ensure all interfaces are setup.
r->wayland.registry = wl_display_get_registry(r->wayland.display);
wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r);
if(wl_display_roundtrip(r->wayland.display) == -1) {
printf("roundtrip failed\n");
r->common.success = MwFALSE;
return;
}
printf("Found globals: \n");
for(i = 0; i < shlen(r->wayland.wl_protocol_map); i++) {
wayland_protocol_t* proto = shget(r->wayland.wl_protocol_map, r->wayland.wl_protocol_map[i].key);
if(proto != NULL) {
printf("%s (%p)\n", r->wayland.wl_protocol_map[i].key, r->wayland.wl_protocol_map[i].value);
} else {
printf("%s (proto is null)\n", r->wayland.wl_protocol_map[i].key, r->wayland.wl_protocol_map[i].value);
}
}
// Check that all globals we require are available
if(
r->wayland.compositor == NULL ||
WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context == NULL ||
WAYLAND_GET_INTERFACE(r->wayland, wl_seat)->context == NULL) {
printf("no wl_shm, wl_compositor, wl_seat, or xdg_wm_base support\n");
r->common.success = MwFALSE;
return;
}
r->wayland.toplevel->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
// Create a wl_surface, a xdg_surface and a xdg_toplevel
r->wayland.surface = wl_compositor_create_surface(r->wayland.compositor);
r->wayland.toplevel->xdg_surface =
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.surface);
r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface);
// setup mandatory listeners
r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure;
r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure;
r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close;
xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r);
xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener,
r);
xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko Wayland App");
xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp");
// Perform the initial commit and wait for the first configure event
region = wl_compositor_create_region(r->wayland.compositor);
wl_region_add(region, 0, 0, r->wayland.ww, r->wayland.wh);
wl_surface_set_opaque_region(r->wayland.surface, region);
wl_surface_commit(r->wayland.surface);
event_loop(r);
wl_region_destroy(region);
// setup decorations if we can
if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) {
zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context;
dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
dec->manager, r->wayland.toplevel->xdg_top_level);
zxdg_toplevel_decoration_v1_set_mode(
dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
} else {
printf("zxdg null\n");
}
// buffer_setup(&r->wayland);
// glGenBuffers(1, &vertex_buffer);
}
static void setup_subsurface(MwLL parent, MwLL r, int x, int y) {
struct wl_compositor* compositor = parent->wayland.compositor;
struct wl_subcompositor* subcompositor = parent->wayland.subcompositor;
struct wl_surface* parent_surface = parent->wayland.surface;
MwLL topmost_parent = parent;
struct wl_region* region;
while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
topmost_parent = topmost_parent->wayland.parent;
}
r->wayland.type = MWLL_WAYLAND_SUBSURFACE;
r->wayland.display = parent->wayland.display;
r->wayland.surface = wl_compositor_create_surface(compositor);
region = wl_compositor_create_region(compositor);
wl_region_add(region, 0, 0, r->wayland.ww, r->wayland.wh);
wl_surface_set_opaque_region(r->wayland.surface, region);
wl_surface_commit(r->wayland.surface);
event_loop(r);
wl_region_destroy(region);
r->wayland.subsurface = wl_subcompositor_get_subsurface(subcompositor, r->wayland.surface, parent_surface);
wl_subsurface_set_position(r->wayland.subsurface, x, y);
// printf("position %d %d\n", x, y);
setup_callbacks(&r->wayland);
r->wayland.registry = wl_display_get_registry(topmost_parent->wayland.display);
r->wayland.display = topmost_parent->wayland.display;
wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r);
if(wl_display_roundtrip(r->wayland.display) == -1) {
printf("roundtrip failed\n");
raise(SIGTRAP);
return;
}
// arrpush(parent->wayland.subsurfaces, r);
r->wayland.configured = MwTRUE;
r->wayland.egl_context = topmost_parent->wayland.egl_context;
r->wayland.egl_display = topmost_parent->wayland.egl_display;
r->wayland.egl_surface = topmost_parent->wayland.egl_surface;
r->wayland.fbo = topmost_parent->wayland.fbo;
r->wayland.fbo_texture = topmost_parent->wayland.fbo_texture;
}
static void framebuffer_action_begin(MwLL handle) {
glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0);
}
static void framebuffer_action_end(MwLL handle) {
glFinish();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
MwLL r;
r = malloc(sizeof(*r));
MwLLCreateCommon(r);
r->common.type = MwLLBackendWayland;
if(width == 0) width = 1;
if(height == 0) height = 1;
r->wayland.ww = width;
r->wayland.wh = height;
printf("%d %d\n", x, y);
r->wayland.parent = parent;
r->wayland.force_redraw = MwFALSE;
r->common.success = MwTRUE;
r->wayland.x = x;
r->wayland.y = y;
if(parent == NULL) {
setup_toplevel(r, x, y);
} else {
setup_subsurface(parent, r, x, y);
}
return r;
}
static void MwLLDestroyImpl(MwLL handle) {
MwLLDestroyCommon(handle);
free(handle);
}
static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) {
*x = handle->wayland.x;
*y = handle->wayland.y;
*w = handle->wayland.ww;
*h = handle->wayland.wh;
}
static void MwLLSetXYImpl(MwLL handle, int x, int y) {
if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
handle->wayland.x = x;
handle->wayland.y = y;
wl_subsurface_set_position(handle->wayland.subsurface, x, y);
MwLLForceRender(handle);
}
}
static void MwLLSetWHImpl(MwLL handle, int w, int h) {
/* Prevent an integer underflow when the w/h is too low */
if((w < 10 || h < 10)) {
handle->wayland.ww = 10;
handle->wayland.wh = 10;
return;
}
handle->wayland.ww = w;
handle->wayland.wh = h;
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
} else {
}
}
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
int i, n;
float maxX = 0, maxY = 0;
float centerX, centerY;
glLineWidth(5);
if(points_count > 3) {
/* To avoid having to do a real triangulation algorithim:
1.) loop through the points once to determine the bounds of the polygon
2.) calculate the center of the polygon
*/
for(i = 0; i < points_count; i++) {
float x = round(handle->wayland.x) + round(points[i].x);
float y = round(handle->wayland.y) + round(points[i].y);
if(x >= maxX) {
maxX = x;
}
if(y >= maxY) {
maxY = y;
}
}
}
centerX = (handle->wayland.x + maxX / 2);
centerY = (handle->wayland.y + maxY / 2);
/* Efficient? No. But at the end of the day it's still not that many polygons, and if a computer can't handle 12 polygons over 6 then it should not be using Wayland anyways */
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
framebuffer_action_begin(handle);
glBegin(GL_TRIANGLES);
for(i = 0; i < points_count; i++) {
float x = round(handle->wayland.x) + round(points[i].x);
float y = round(handle->wayland.y) + round(points[i].y);
glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0);
glVertex2f(x, y);
if(points_count > 4) {
glVertex2f(maxX, maxY);
glVertex2f(x, y);
}
}
glEnd();
// glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
framebuffer_action_end(handle);
}
static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
//
}
static void MwLLEndDrawImpl(MwLL handle) {
int w, h;
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
w = handle->wayland.ww;
h = handle->wayland.wh;
} else {
MwLL parent = handle->wayland.parent;
w = parent->wayland.ww;
h = parent->wayland.wh;
}
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0, 0, 0, 1);
glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture);
glColor3f(1.0, 1.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1);
glVertex2f(0, 0);
glTexCoord2f(1, 1);
glVertex2f(w, 0);
glTexCoord2f(1, 0.0f);
glVertex2f(w, h);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0, h);
glEnd();
glFinish();
wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) {
printf("error swapping buffers! %0X\n", eglGetError());
} else {
wl_surface_commit(handle->wayland.surface);
}
}
static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) {
MwLLColor c = malloc(sizeof(*c));
c->common.red = r;
c->common.blue = b;
c->common.green = g;
return c;
}
static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) {
c->common.red = r;
c->common.blue = b;
c->common.green = g;
}
static void MwLLFreeColorImpl(MwLLColor color) {
free(color);
}
static int MwLLPendingImpl(MwLL handle) {
return event_loop(handle) || handle->wayland.force_redraw;
}
static void MwLLNextEventImpl(MwLL handle) {
MwBool render = handle->wayland.force_redraw;
if(render) {
int x, y;
unsigned int w, h;
MwLLGetXYWH(handle, &x, &y, &w, &h);
MwLLDispatch(handle, draw, NULL);
handle->wayland.force_redraw = MwFALSE;
}
}
static void MwLLSetTitleImpl(MwLL handle, const char* title) {
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title);
}
}
static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) {
MwLLPixmap r = malloc(sizeof(*r));
r->common.width = width;
r->common.height = height;
r->common.raw = data;
r->wayland.texture = 0;
glGenTextures(1, &r->wayland.texture);
glBindTexture(GL_TEXTURE_2D, r->wayland.texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
MwLLPixmapUpdate(r);
return r;
}
static void MwLLPixmapUpdateImpl(MwLLPixmap r) {
glBindTexture(GL_TEXTURE_2D, r->wayland.texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r->common.width, r->common.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, r->common.raw);
glBindTexture(GL_TEXTURE_2D, 0);
}
static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) {
glDeleteTextures(1, &pixmap->wayland.texture);
free(pixmap);
}
static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) {
int x, y;
glColor3f(1.0, 1.0, 1.0);
x = handle->wayland.x + rect->x;
y = handle->wayland.y + rect->y;
glBindTexture(GL_TEXTURE_2D, pixmap->wayland.texture);
glActiveTexture(pixmap->wayland.texture);
framebuffer_action_begin(handle);
// glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 1, 1);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0);
glVertex2f(x, y);
glTexCoord2f(1, 0);
glVertex2f(x + rect->width, y);
glTexCoord2f(1, 1);
glVertex2f(x + rect->width, y + rect->height);
glTexCoord2f(0.0f, 1);
glVertex2f(x, y + rect->height);
glEnd();
glFinish();
framebuffer_action_end(handle);
}
static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {
}
static void MwLLForceRenderImpl(MwLL handle) {
wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
wl_surface_commit(handle->wayland.surface);
handle->wayland.force_redraw = MwTRUE;
}
static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) {
}
static void MwLLDetachImpl(MwLL handle, MwPoint* point) {
}
static void MwLLShowImpl(MwLL handle, int show) {
}
static void MwLLMakePopupImpl(MwLL handle, MwLL parent) {
}
static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) {
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny);
xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy);
}
}
static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) {
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context != NULL) {
zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context;
dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
dec->manager, handle->wayland.toplevel->xdg_top_level);
zxdg_toplevel_decoration_v1_set_mode(
dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
} else {
// TODO: hide our custom window decorations when we have them.
printf("zxdg null\n");
}
}
}
static void MwLLFocusImpl(MwLL handle) {
}
static void MwLLGrabPointerImpl(MwLL handle, int toggle) {
}
static void MwLLSetClipboardImpl(MwLL handle, const char* text) {
}
static char* MwLLGetClipboardImpl(MwLL handle) {
char* r = NULL;
return r;
}
static void MwLLMakeToolWindowImpl(MwLL handle) {
}
static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) {
}
static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) {
}
static void MwLLBeginStateChangeImpl(MwLL handle) {
MwLLShow(handle, 0);
}
static void MwLLEndStateChangeImpl(MwLL handle) {
MwLLShow(handle, 1);
}
static int MwLLWaylandCallInitImpl(void) {
#ifdef __linux__
if(strcmp(getenv("XDG_SESSION_TYPE"), "wayland")) {
return 1;
}
#endif
return 0;
}
#include "call.c"
CALL(Wayland);

View file

@ -256,6 +256,8 @@ static void MwLLDestroyImpl(MwLL handle) {
free(handle); free(handle);
} }
static void MwLLEndDrawImpl(MwLL handle) {}
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
int i; int i;
XPoint* p = malloc(sizeof(*p) * points_count); XPoint* p = malloc(sizeof(*p) * points_count);
@ -395,10 +397,6 @@ static void MwLLFreeColorImpl(MwLLColor color) {
free(color); free(color);
} }
static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) {
XSetWindowBackground(handle->x11.display, handle->x11.window, color->x11.pixel);
}
static int MwLLPendingImpl(MwLL handle) { static int MwLLPendingImpl(MwLL handle) {
XEvent ev; XEvent ev;
if(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { if(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) {
@ -1019,7 +1017,6 @@ static void MwLLEndStateChangeImpl(MwLL handle) {
} }
static int MwLLX11CallInitImpl(void) { static int MwLLX11CallInitImpl(void) {
/* TODO: check properly */
return 0; return 0;
} }

View file

@ -1,10 +1,13 @@
/* $Id$ */ /* $Id$ */
#include <Mw/Milsko.h> #include <Mw/Milsko.h>
#include <wayland-util.h>
#include "../external/stb_ds.h" #include "../external/stb_ds.h"
#include "Mw/LowLevel.h"
static void lldrawhandler(MwLL handle, void* data) { static void lldrawhandler(MwLL handle, void* data) {
MwWidget h = (MwWidget)handle->common.user; MwWidget h = (MwWidget)handle->common.user;
int ind;
(void)data; (void)data;
@ -12,6 +15,12 @@ static void lldrawhandler(MwLL handle, void* data) {
MwDispatch(h, draw); MwDispatch(h, draw);
if(h->draw_inject != NULL) h->draw_inject(h); if(h->draw_inject != NULL) h->draw_inject(h);
MwDispatchUserHandler(h, MwNdrawHandler, NULL); MwDispatchUserHandler(h, MwNdrawHandler, NULL);
if(h->parent == NULL) {
MwLLEndDraw(h->lowlevel);
} else if(h->parent->lowlevel == NULL) {
MwLLEndDraw(h->lowlevel);
}
} }
static void lluphandler(MwLL handle, void* data) { static void lluphandler(MwLL handle, void* data) {
@ -295,7 +304,10 @@ int MwStep(MwWidget handle) {
arrfree(widgets); arrfree(widgets);
handle->prop_event = 0; handle->prop_event = 0;
if(handle->lowlevel != NULL && MwLLPending(handle->lowlevel)) MwLLNextEvent(handle->lowlevel);
if(handle->lowlevel != NULL && MwLLPending(handle->lowlevel))
MwLLNextEvent(handle->lowlevel);
handle->prop_event = 1; handle->prop_event = 1;
clean_destroy_queue(handle); clean_destroy_queue(handle);
@ -378,11 +390,7 @@ void MwSetText(MwWidget handle, const char* key, const char* value) {
shput(handle->text, key, v); shput(handle->text, key, v);
} }
if(handle->prop_event) MwDispatch3(handle, prop_change, key); if(handle->prop_event) MwDispatch3(handle, prop_change, key);
if(strcmp(key, MwNbackground) == 0) {
MwLLColor c = MwParseColor(handle, value);
MwLLSetBackground(handle->lowlevel, c);
MwLLFreeColor(c);
}
if(strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0) { if(strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0) {
MwForceRender(handle); MwForceRender(handle);
} }
@ -687,6 +695,9 @@ MwWidget MwGetParent(MwWidget handle) {
typedef int (*call_t)(void); typedef int (*call_t)(void);
int MwLibraryInit(void) { int MwLibraryInit(void) {
call_t calls[] = { call_t calls[] = {
#ifdef USE_WAYLAND
MwLLWaylandCallInit,
#endif
#ifdef USE_X11 #ifdef USE_X11
MwLLX11CallInit, MwLLX11CallInit,
#endif #endif

View file

@ -1,5 +1,7 @@
/* $Id$ */ /* $Id$ */
#include "Mw/LowLevel.h"
#include <Mw/Milsko.h> #include <Mw/Milsko.h>
#include <stdio.h>
#ifdef USE_STB_IMAGE #ifdef USE_STB_IMAGE
#include "../external/stb_image.h" #include "../external/stb_image.h"
@ -484,6 +486,7 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert,
p4[2].y = rect->y + s * border; p4[2].y = rect->y + s * border;
} }
MwLLPolygon(handle->lowlevel, p4, 3, col); MwLLPolygon(handle->lowlevel, p4, 3, col);
if(color != col) MwLLFreeColor(col); if(color != col) MwLLFreeColor(col);
MwLLFreeColor(lighter); MwLLFreeColor(lighter);

View file

@ -7,6 +7,8 @@ void (*MwLLDestroy)(MwLL handle);
void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color);
void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color);
void (*MwLLEndDraw)(MwLL handle);
MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b);
void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b);
void (*MwLLFreeColor)(MwLLColor color); void (*MwLLFreeColor)(MwLLColor color);
@ -40,8 +42,6 @@ void (*MwLLMakePopup)(MwLL handle, MwLL parent);
void (*MwLLBeginStateChange)(MwLL handle); void (*MwLLBeginStateChange)(MwLL handle);
void (*MwLLEndStateChange)(MwLL handle); void (*MwLLEndStateChange)(MwLL handle);
void (*MwLLSetBackground)(MwLL handle, MwLLColor color);
void (*MwLLFocus)(MwLL handle); void (*MwLLFocus)(MwLL handle);
void (*MwLLGrabPointer)(MwLL handle, int toggle); void (*MwLLGrabPointer)(MwLL handle, int toggle);