temporairly try and use cairo again

This commit is contained in:
IoIxD 2025-12-07 18:18:43 -07:00
commit 86eb481aa3
3 changed files with 199 additions and 432 deletions

View file

@ -13,13 +13,34 @@
#include <wayland-client-protocol.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <cairo/cairo.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input-event-codes.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <wayland-client-protocol.h>
#include "Mw/BaseTypes.h"
#include "Mw/LowLevel.h"
#include <sys/mman.h>
#include <wayland-egl-core.h>
#include <wayland-util.h>
/* TODO: find out what FreeBSD and such wants us to include */
#include <linux/input.h>
MWDECL int MwLLWaylandCallInit(void);
#ifndef WL_PROTOCOLS_DEFINED
@ -89,18 +110,19 @@ struct _MwLLWayland {
MwU32 x, y, ww, wh;
MwPoint cur_mouse_pos;
int last_serial;
cairo_surface_t* cairo_surface;
void* mapped_buffer;
MwLL parent;
GLuint fbo;
unsigned int fbo_texture;
// GLuint fbo;
// unsigned int fbo_texture;
EGLNativeWindowType egl_window_native;
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
EGLConfig egl_config;
// EGLNativeWindowType egl_window_native;
// EGLDisplay egl_display;
// EGLContext egl_context;
// EGLSurface egl_surface;
// EGLConfig egl_config;
};
struct _MwLLWaylandColor {
@ -109,7 +131,7 @@ struct _MwLLWaylandColor {
struct _MwLLWaylandPixmap {
struct _MwLLCommonPixmap common;
GLuint texture;
// GLuint texture;
};
#endif

View file

@ -29,7 +29,7 @@ if (grep(/^gdi$/, @backends)) {
if (grep(/^wayland$/, @backends)) {
add_cflags("-DUSE_WAYLAND");
new_object("src/backend/wayland.c");
add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon");
add_libs("-lcairo -lwayland-client -lxkbcommon");
scan_wayland_protocol("stable", "xdg-shell","");
scan_wayland_protocol("stable", "tablet","-v2");

View file

@ -1,37 +1,7 @@
#include <Mw/Milsko.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input-event-codes.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.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>
/* TODO: find out what FreeBSD and such wants us to include */
#include <linux/input.h>
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus;
/*
callback todo:
void (*up)(MwLL handle, void* data);
@ -78,6 +48,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, uint32_t t
self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y);
p.point = self->wayland.cur_mouse_pos;
MwLLDispatch(self, move, &p);
MwLLForceRender(self);
};
static void pointer_button(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
MwLL self = data;
@ -104,6 +75,8 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, uint32_t s
break;
}
}
printf("what\n");
MwLLForceRender(self);
};
static void pointer_axis(void* data, struct wl_pointer* wl_pointer, uint32_t time,
uint32_t axis, wl_fixed_t value) {};
@ -140,6 +113,62 @@ void xdg_wm_base_ping(void* data,
xdg_wm_base_pong(xdg_wm_base, serial);
};
static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
return NULL;
}
static void buffer_setup(struct _MwLLWayland* wayland) {
struct wl_shm_pool* pool;
struct wl_buffer* buffer;
int x, y;
int stride = wayland->ww * 4;
int fd;
MwU32 size = wayland->ww * wayland->wh * 4;
char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX";
fd = mkstemp(temp_name);
unlink(temp_name);
if(posix_fallocate(fd, 0, size) != 0) {
printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno));
close(fd);
return;
}
if(ftruncate(fd, size) != 0) {
printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno));
close(fd);
return;
}
wayland->mapped_buffer = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
memset(wayland->mapped_buffer, 0xFF, size);
// wayland->mapped_buffer_size = size;
wayland->cairo_surface = cairo_image_surface_create_for_data(wayland->mapped_buffer,
CAIRO_FORMAT_ARGB32,
wayland->ww,
wayland->wh,
stride);
fsync(fd);
if(!(pool = wl_shm_create_pool(wayland->shm, fd, size))) {
printf("failure setting up wl_shm: could not create pool.\n");
}
buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888);
if(wayland->configured) {
wl_surface_attach(wayland->surface, buffer, 0, 0);
wl_surface_commit(wayland->surface);
}
wl_buffer_destroy(buffer);
wl_shm_pool_destroy(pool);
close(fd);
}
static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
proto->listener = malloc(sizeof(struct wl_seat_listener));
@ -205,169 +234,6 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _
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;
return MwTRUE;
}
static void egl_resetup(MwLL handle) {
int err;
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 recursive_draw(MwLL handle) {
int i;
if(handle->wayland.subwidgets != NULL) {
for(i = 0; i < arrlen(handle->wayland.subwidgets); i++) {
MwLLDispatch(handle->wayland.subwidgets[i], draw, NULL);
recursive_draw(handle->wayland.subwidgets[i]);
}
}
}
static void recursive_resize(MwLL handle) {
int i;
if(handle->wayland.subwidgets != NULL) {
@ -382,8 +248,7 @@ 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");
MwLL self = data;
if(width == 0 || height == 0) {
width = self->wayland.ww;
@ -401,15 +266,6 @@ static void xdg_toplevel_configure(void* data,
MwLLDispatch(self, resize, NULL);
recursive_resize(self);
if(!self->wayland.egl_setup) {
self->wayland.egl_setup = egl_setup(self, width, height);
MwLLForceRender(self);
} else {
wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0);
self->wayland.egl_do_resetup = MwTRUE;
egl_resetup(self);
}
return;
};
@ -442,69 +298,20 @@ static void xdg_surface_configure(
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;
MwLL topmost_parent = handle->wayland.parent;
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) {
static MwBool flush_display(struct wl_display* display) {
while(wl_display_flush(display) == -1) {
if(errno != EAGAIN) {
return MwFALSE;
}
struct pollfd fd = {wl_display_get_fd(display), POLL_OUT};
while(poll(&fd, 1, -1) == -1) {
if(errno != EINTR && errno != EAGAIN) {
wl_display_cancel_read(wayland->display);
MwLLDispatch(handle, close, NULL);
return 0;
}
if(errno != EINTR && errno != EAGAIN)
return MwFALSE;
}
}
/*
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);
recursive_draw(handle);
}
}
return 0;
return MwTRUE;
}
#define WL_INTERFACE(interface) \
@ -519,6 +326,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) {
WL_INTERFACE(wl_compositor);
WL_INTERFACE(wl_subcompositor);
WL_INTERFACE(wl_seat);
WL_INTERFACE(wl_shm);
if(wayland->type == MWLL_WAYLAND_TOPLEVEL) {
WL_INTERFACE(xdg_wm_base);
WL_INTERFACE(zxdg_decoration_manager_v1);
@ -588,7 +396,8 @@ static void setup_toplevel(MwLL r, int x, int y) {
// Perform the initial commit and wait for the first configure event
wl_surface_commit(r->wayland.surface);
event_loop(r);
while(wl_display_dispatch(r->wayland.display) != -1 && !r->wayland.configured) {
}
// setup decorations if we can
if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) {
@ -606,6 +415,9 @@ static void setup_toplevel(MwLL r, int x, int y) {
// buffer_setup(&r->wayland);
// glGenBuffers(1, &vertex_buffer);
//
buffer_setup(&r->wayland);
wl_surface_commit(r->wayland.surface);
}
static void setup_subsurface(MwLL parent, MwLL r, int x, int y) {
@ -629,7 +441,6 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y) {
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);
@ -654,23 +465,13 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y) {
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;
arrpush(parent->wayland.subwidgets, r);
}
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) {
@ -706,6 +507,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
setup_subsurface(parent, r, x, y);
}
buffer_setup(&r->wayland);
printf("test\n");
return r;
}
@ -748,122 +552,43 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) {
}
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
int i, n;
float maxX = 0, maxY = 0;
float centerX, centerY;
int doLoopback = MwFALSE;
int i = 0;
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
cairo_t* cairo = cairo_create(handle->wayland.cairo_surface);
cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.);
cairo_set_line_width(cairo, 0.1);
cairo_set_fill_rule(cairo, CAIRO_FILL_RULE_EVEN_ODD);
*/
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;
}
}
cairo_new_path(cairo);
for(; i < points_count; i++) {
cairo_line_to(cairo, points[i].x, points[i].y);
}
centerX = (handle->wayland.x + maxX / 2);
centerY = (handle->wayland.y + maxY / 2);
cairo_close_path(cairo);
/* 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 */
framebuffer_action_begin(handle);
if(points_count == 3) {
glBegin(GL_TRIANGLES);
} else if((points_count % 3) == 0) {
glBegin(GL_POLYGON);
} else {
glBegin(GL_TRIANGLE_FAN);
doLoopback = MwTRUE;
}
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(doLoopback) {
glVertex2f(maxX, maxY);
glVertex2f(x, y);
}
}
glEnd();
glColor3f(0, 0, 0);
framebuffer_action_end(handle);
// cairo_paint(cairo);
cairo_stroke_preserve(cairo);
cairo_fill(cairo);
cairo_destroy(cairo);
}
static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
int i;
MwPoint p1 = points[0];
MwPoint p2 = points[1];
int i;
glLineWidth(1);
cairo_t* cairo = cairo_create(handle->wayland.cairo_surface);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_line_width(cairo, 1);
cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.);
cairo_paint(cairo);
framebuffer_action_begin(handle);
glBegin(GL_LINES);
for(i = 0; i < 2; 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);
}
glEnd();
glColor3f(0, 0, 0);
framebuffer_action_end(handle);
cairo_move_to(cairo, p1.x, p1.y);
cairo_line_to(cairo, p2.x, p2.y);
cairo_fill(cairo);
cairo_destroy(cairo);
}
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;
}
recursive_draw(handle);
glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture);
// glClear(GL_COLOR_BUFFER_BIT);
// glClearColor(1.0, 0, 0, 1);
glColor3f(1.0, 1.0, 1.0);
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) {
@ -887,15 +612,71 @@ static void MwLLFreeColorImpl(MwLLColor color) {
}
static int MwLLPendingImpl(MwLL handle) {
if(wl_display_dispatch_pending(handle->wayland.display) == 0) {
enum {
DISPLAY_FD,
KEYREPEAT_FD,
CURSOR_FD
};
struct pollfd fd;
int timeout = 1;
if(handle->wayland.force_redraw) {
return 1;
}
return event_loop(handle) || handle->wayland.force_redraw;
if(handle->wayland.display == NULL) {
return 0;
}
fd.fd = wl_display_get_fd(handle->wayland.display);
fd.events = POLLIN;
while(wl_display_prepare_read(handle->wayland.display) != 0) {
if(wl_display_dispatch_pending(handle->wayland.display) > 0) {
return 0;
}
}
// If an error other than EAGAIN happens, we have likely been disconnected
// from the Wayland session
if(!flush_display(handle->wayland.display)) {
wl_display_cancel_read(handle->wayland.display);
MwLLDispatch(handle, close, NULL);
// handle->wayland.toplevel->running = MwFALSE;
return 0;
}
// Condition where no events are being sent.
if(!poll(&fd, 1, timeout)) {
wl_display_cancel_read(handle->wayland.display);
// In this case, we need to commit the surface for any animations, etc.
wl_surface_commit(handle->wayland.surface);
return 0;
}
if(fd.revents & POLLIN) {
wl_display_read_events(handle->wayland.display);
if(wl_display_dispatch_pending(handle->wayland.display) > 0) {
}
} else {
wl_display_cancel_read(handle->wayland.display);
}
return 1;
}
static void MwLLNextEventImpl(MwLL handle) {
MwBool render = handle->wayland.force_redraw;
MwBool render;
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;
}
}
@ -909,59 +690,23 @@ static void MwLLSetTitleImpl(MwLL handle, const char* 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);
r->common.width = width;
r->common.height = height;
r->common.raw = data;
// r->wayland.texture = 0;
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);
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) {