[wayland_gtk_egl] sort out reusable csd layer from gtk specifics

main
Allen Webster 2026-03-04 13:35:43 -08:00
parent e9c46a04f0
commit f56f60c2fb
2 changed files with 267 additions and 242 deletions

View File

@ -12,12 +12,17 @@ exit 0
#define _GNU_SOURCE #define _GNU_SOURCE
#define HAS_DBUS
#define HAVE_MKOSTEMP
#define HAVE_MEMFD_CREATE
#define HAVE_POSIX_FALLOCATE
#include <wayland-client.h> #include <wayland-client.h>
#include <wayland-client-core.h> #include <wayland-client-core.h>
#include <wayland-cursor.h> #include <wayland-cursor.h>
#include <wayland-egl.h> #include <wayland-egl.h>
/*~ NOTE: wayland-egl.h *before* EGL/ */ /*~ NOTE: wayland-egl.h *before* EGL includes */
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <GL/glcorearb.h> #include <GL/glcorearb.h>
@ -62,10 +67,9 @@ GL_FUNCS_XLIST(X)
static Ctx ctx = {0}; static Ctx ctx = {0};
static void static void
shm_format(void *udata, struct wl_shm *wl_shm, uint32_t format){ shm_format(void *udata, struct wl_shm *wl_shm, uint32_t format){}
}
const struct wl_shm_listener shm_listener = { static const struct wl_shm_listener shm_listener = {
shm_format shm_format
}; };
@ -74,7 +78,7 @@ xdg_wm_base_ping(void *udata, struct xdg_wm_base *xdg_wm_base, uint32_t serial){
xdg_wm_base_pong(xdg_wm_base, serial); xdg_wm_base_pong(xdg_wm_base, serial);
} }
const struct xdg_wm_base_listener xdg_wm_base_listener = { static const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_wm_base_ping xdg_wm_base_ping
}; };
@ -173,7 +177,7 @@ pointer_axis(void *udata, struct wl_pointer *wl_pointer,
printf("pointer_axis %u,%d\n", axis, v); printf("pointer_axis %u,%d\n", axis, v);
} }
const struct wl_pointer_listener pointer_listener = { static const struct wl_pointer_listener pointer_listener = {
pointer_enter, pointer_enter,
pointer_leave, pointer_leave,
pointer_motion, pointer_motion,
@ -194,10 +198,9 @@ seat_capabilities(void *udata, struct wl_seat *wl_seat, uint32_t capabilities){
} }
static void static void
seat_name(void *udata, struct wl_seat *wl_seat, const char *name){ seat_name(void *udata, struct wl_seat *wl_seat, const char *name){}
}
const struct wl_seat_listener seat_listener = { static const struct wl_seat_listener seat_listener = {
seat_capabilities, seat_capabilities,
seat_name seat_name
}; };
@ -208,21 +211,28 @@ registry_global(void *udata, struct wl_registry *wl_registry,
uint32_t version){ uint32_t version){
if (strcmp(interface, "wl_compositor") == 0){ if (strcmp(interface, "wl_compositor") == 0){
ctx.wl_compositor = (struct wl_compositor*) ctx.wl_compositor = (struct wl_compositor*)
wl_registry_bind(wl_registry, name, &wl_compositor_interface, Min(version, 4)); wl_registry_bind(wl_registry, name, &wl_compositor_interface,
CSD_Min(version, 4));
} }
else if (strcmp(interface, "wl_subcompositor") == 0){ else if (strcmp(interface, "wl_subcompositor") == 0){
ctx.wl_subcompositor = wl_registry_bind(ctx.wl_registry, name, &wl_subcompositor_interface, 1); ctx.wl_subcompositor = wl_registry_bind(ctx.wl_registry, name,
&wl_subcompositor_interface, 1);
} }
else if (strcmp(interface, "wl_shm") == 0){ else if (strcmp(interface, "wl_shm") == 0){
ctx.wl_shm = wl_registry_bind(ctx.wl_registry, name, &wl_shm_interface, 1); ctx.wl_shm = wl_registry_bind(ctx.wl_registry, name, &wl_shm_interface, 1);
wl_shm_add_listener(ctx.wl_shm, &shm_listener, 0); wl_shm_add_listener(ctx.wl_shm, &shm_listener, 0);
} }
else if (!strcmp(interface, xdg_wm_base_interface.name)){ else if (!strcmp(interface, xdg_wm_base_interface.name)){
ctx.xdg_wm_base = wl_registry_bind(ctx.wl_registry, name, &xdg_wm_base_interface, Min(version, 2)); ctx.xdg_wm_base = wl_registry_bind(ctx.wl_registry, name,
&xdg_wm_base_interface,
CSD_Min(version, 2));
xdg_wm_base_add_listener(ctx.xdg_wm_base, &xdg_wm_base_listener, 0); xdg_wm_base_add_listener(ctx.xdg_wm_base, &xdg_wm_base_listener, 0);
} }
else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name)){ else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name)){
ctx.zxdg_decoration_manager = wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, Min(version, 2)); ctx.zxdg_decoration_manager =
wl_registry_bind(wl_registry, name,
&zxdg_decoration_manager_v1_interface,
CSD_Min(version, 2));
} }
else if (strcmp(interface, "wl_seat") == 0){ else if (strcmp(interface, "wl_seat") == 0){
ctx.wl_seat = wl_registry_bind(ctx.wl_registry, name, &wl_seat_interface, 3); ctx.wl_seat = wl_registry_bind(ctx.wl_registry, name, &wl_seat_interface, 3);
@ -233,10 +243,9 @@ registry_global(void *udata, struct wl_registry *wl_registry,
static void static void
registry_global_remove(void *udata, struct wl_registry *registry, registry_global_remove(void *udata, struct wl_registry *registry,
uint32_t name){ uint32_t name){}
}
const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {
registry_global, registry_global,
registry_global_remove, registry_global_remove,
}; };
@ -247,7 +256,9 @@ xdg_surface_configure(void *udata, struct xdg_surface *xdg_surface,
ctx.config_staged.serial = serial; ctx.config_staged.serial = serial;
} }
const struct xdg_surface_listener xdg_surface_listener = { xdg_surface_configure, }; static const struct xdg_surface_listener xdg_surface_listener = {
xdg_surface_configure
};
static void static void
xdg_toplevel_configure(void *udata, struct xdg_toplevel *xdg_toplevel, xdg_toplevel_configure(void *udata, struct xdg_toplevel *xdg_toplevel,
@ -270,15 +281,13 @@ xdg_toplevel_close(void *udata, struct xdg_toplevel *xdg_toplevel){
static void static void
xdg_toplevel_configure_bounds(void *udata, struct xdg_toplevel *xdg_toplevel, xdg_toplevel_configure_bounds(void *udata, struct xdg_toplevel *xdg_toplevel,
int32_t w, int32_t h){ int32_t w, int32_t h){}
}
static void static void
xdg_toplevel_wm_capabilities(void *udata, struct xdg_toplevel *xdg_toplevel, xdg_toplevel_wm_capabilities(void *udata, struct xdg_toplevel *xdg_toplevel,
struct wl_array *capabilities){ struct wl_array *capabilities){}
}
const struct xdg_toplevel_listener xdg_toplevel_listener = { static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_configure, xdg_toplevel_configure,
xdg_toplevel_close, xdg_toplevel_close,
xdg_toplevel_configure_bounds, xdg_toplevel_configure_bounds,
@ -291,14 +300,15 @@ xdg_toplevel_decoration_configure(void *udata, struct zxdg_toplevel_decoration_v
ctx.config_staged.decoration_mode = mode; ctx.config_staged.decoration_mode = mode;
} }
const struct zxdg_toplevel_decoration_v1_listener zxdg_toplevel_decoration_listener = { static const struct zxdg_toplevel_decoration_v1_listener
zxdg_toplevel_decoration_listener = {
xdg_toplevel_decoration_configure xdg_toplevel_decoration_configure
}; };
int main(){ int main(){
/* desktop settings */ /* desktop settings */
ctx.color_scheme = ds_get_color_scheme(); ctx.color_scheme = csd_desktop_get_color_scheme();
ctx.cursor_theme = ds_get_cursor_theme(); ctx.cursor_theme = csd_desktop_get_cursor_theme();
/* setup gtk */ /* setup gtk */
csd_gtk_init(); csd_gtk_init();
@ -317,15 +327,15 @@ int main(){
ctx.wl_shm); ctx.wl_shm);
#define X(k,n) ctx.wl_cursors[k] = wl_cursor_theme_get_cursor(ctx.wl_cursor_theme, n); #define X(k,n) ctx.wl_cursors[k] = wl_cursor_theme_get_cursor(ctx.wl_cursor_theme, n);
X(CursorShape_Pointer, "left_ptr"); X(CSD_CursorShape_Pointer, "left_ptr");
X(CursorShape_Resize_Top, "top_side"); X(CSD_CursorShape_Resize_Top, "top_side");
X(CursorShape_Resize_Bottom, "bottom_side"); X(CSD_CursorShape_Resize_Bottom, "bottom_side");
X(CursorShape_Resize_Left, "left_side"); X(CSD_CursorShape_Resize_Left, "left_side");
X(CursorShape_Resize_Right, "right_side"); X(CSD_CursorShape_Resize_Right, "right_side");
X(CursorShape_Resize_TopLeft, "top_left_corner"); X(CSD_CursorShape_Resize_TopLeft, "top_left_corner");
X(CursorShape_Resize_BottomLeft, "bottom_left_corner"); X(CSD_CursorShape_Resize_BottomLeft, "bottom_left_corner");
X(CursorShape_Resize_TopRight, "top_right_corner"); X(CSD_CursorShape_Resize_TopRight, "top_right_corner");
X(CursorShape_Resize_BottomRight, "bottom_right_corner"); X(CSD_CursorShape_Resize_BottomRight, "bottom_right_corner");
#undef X #undef X
} }
@ -495,21 +505,21 @@ int main(){
d = ctx.dim[i]; d = ctx.dim[i];
ctx.config.dim[i] = d + ctx.csd_dim[i]; ctx.config.dim[i] = d + ctx.csd_dim[i];
} }
d = ClampBot(d, ctx.mmbox[i][0]); d = CSD_ClampBot(d, ctx.mmbox[i][0]);
d = ClampTop(d, ctx.mmbox[i][1]); d = CSD_ClampTop(d, ctx.mmbox[i][1]);
d = ClampBot(d, ctx.csd_frame.minbox[i]); d = CSD_ClampBot(d, ctx.csd_frame.minbox[i]);
ctx.dim[i] = d; ctx.dim[i] = d;
} }
ctx.handled_first_size = 1; ctx.handled_first_size = 1;
/* window size commit */ /* window size commit */
if (!(ctx.control_flags & WindowControlFlag_Resize)){ if (!(ctx.control_flags & CSD_WindowControlFlag_Resize)){
xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]);
xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]);
} }
else{ else{
for (int i = 0; i < 2; i += 1){ for (int i = 0; i < 2; i += 1){
int32_t mw = ClampBot(ctx.mmbox[0][i], ctx.csd_frame.minbox[i]) + ctx.csd_dim[0]; int32_t mw = CSD_ClampBot(ctx.mmbox[0][i], ctx.csd_frame.minbox[i]) + ctx.csd_dim[0];
int32_t mh = ctx.mmbox[1][i] + ctx.csd_dim[1]; int32_t mh = ctx.mmbox[1][i] + ctx.csd_dim[1];
if (i == 0){ if (i == 0){
xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, mw, mh); xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, mw, mh);
@ -527,7 +537,7 @@ int main(){
wl_egl_window_resize(ctx.main_wl_egl_window, ctx.dim[0], ctx.dim[1], 0, 0); wl_egl_window_resize(ctx.main_wl_egl_window, ctx.dim[0], ctx.dim[1], 0, 0);
/* frame update and render */ /* frame update and render */
ctx.cursor_shape = CursorShape_Pointer; ctx.cursor_shape = CSD_CursorShape_Pointer;
csd_gtk_update_and_render(); csd_gtk_update_and_render();
/* app update & render */ /* app update & render */
@ -573,8 +583,7 @@ csd_subsurface_new(void){
CSD_SubSurface result = {0}; CSD_SubSurface result = {0};
result.wl_surface = wl_compositor_create_surface(ctx.wl_compositor); result.wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
result.wl_subsurface = result.wl_subsurface =
wl_subcompositor_get_subsurface(ctx.wl_subcompositor, wl_subcompositor_get_subsurface(ctx.wl_subcompositor, result.wl_surface,
result.wl_surface,
ctx.main_wl_surface); ctx.main_wl_surface);
return(result); return(result);
} }
@ -592,11 +601,11 @@ csd_subsurface_buffer_clear(CSD_SubSurface *subsurface){
} }
static void static void
csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, int32_t dim[2]){ csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, CSD_S32 dim[2]){
int stride = 4*dim[0]; int stride = 4*dim[0];
uint64_t size = 4*dim[0]*dim[1]; uint64_t size = 4*dim[0]*dim[1];
int fd = os_create_anonymous_file(size); int fd = csd_os_create_anonymous_file(size);
if (fd >= 0){ if (fd >= 0){
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data != MAP_FAILED){ if (data != MAP_FAILED){
@ -619,7 +628,7 @@ csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, int32_t dim[2]){
} }
static void static void
csd_subsurface_set_position(CSD_SubSurface *subsurface, int32_t x, int32_t y){ csd_subsurface_set_position(CSD_SubSurface *subsurface, CSD_S32 x, CSD_S32 y){
wl_subsurface_set_position(subsurface->wl_subsurface, x, y); wl_subsurface_set_position(subsurface->wl_subsurface, x, y);
subsurface->p[0] = x; subsurface->p[0] = x;
subsurface->p[1] = y; subsurface->p[1] = y;
@ -634,25 +643,25 @@ csd_subsurface_commit(CSD_SubSurface *subsurface){
wl_surface_commit(subsurface->wl_surface); wl_surface_commit(subsurface->wl_surface);
} }
static WindowFlags static CSD_WindowFlags
csd_window_flags_from_states_array(struct wl_array *states){ csd_window_flags_from_states_array(struct wl_array *states){
WindowFlags flags = 0; CSD_WindowFlags flags = 0;
uint32_t *p; uint32_t *p;
wl_array_for_each(p, states){ wl_array_for_each(p, states){
switch (*p) { switch (*p) {
case XDG_TOPLEVEL_STATE_FULLSCREEN: flags |= WindowFlag_IsFullscreen; break; case XDG_TOPLEVEL_STATE_FULLSCREEN: flags |= CSD_WindowFlag_IsFullscreen; break;
case XDG_TOPLEVEL_STATE_MAXIMIZED: flags |= WindowFlag_IsMax; break; case XDG_TOPLEVEL_STATE_MAXIMIZED: flags |= CSD_WindowFlag_IsMax; break;
case XDG_TOPLEVEL_STATE_ACTIVATED: flags |= WindowFlag_IsActivated; break; case XDG_TOPLEVEL_STATE_ACTIVATED: flags |= CSD_WindowFlag_IsActivated; break;
case XDG_TOPLEVEL_STATE_TILED_LEFT: flags |= WindowFlag_IsTiledLeft; break; case XDG_TOPLEVEL_STATE_TILED_LEFT: flags |= CSD_WindowFlag_IsTiledLeft; break;
case XDG_TOPLEVEL_STATE_TILED_RIGHT: flags |= WindowFlag_IsTiledRight; break; case XDG_TOPLEVEL_STATE_TILED_RIGHT: flags |= CSD_WindowFlag_IsTiledRight; break;
case XDG_TOPLEVEL_STATE_TILED_TOP: flags |= WindowFlag_IsTiledTop; break; case XDG_TOPLEVEL_STATE_TILED_TOP: flags |= CSD_WindowFlag_IsTiledTop; break;
case XDG_TOPLEVEL_STATE_TILED_BOTTOM: flags |= WindowFlag_IsTiledBottom; break; case XDG_TOPLEVEL_STATE_TILED_BOTTOM: flags |= CSD_WindowFlag_IsTiledBottom; break;
case XDG_TOPLEVEL_STATE_RESIZING: flags |= WindowFlag_IsResizing; break; case XDG_TOPLEVEL_STATE_RESIZING: flags |= CSD_WindowFlag_IsResizing; break;
case XDG_TOPLEVEL_STATE_SUSPENDED: flags |= WindowFlag_IsSuspended; break; case XDG_TOPLEVEL_STATE_SUSPENDED: flags |= CSD_WindowFlag_IsSuspended; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: flags |= WindowFlag_IsConstrainedLeft; break; case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: flags |= CSD_WindowFlag_IsConstrainedLeft; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: flags |= WindowFlag_IsConstrainedRight; break; case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: flags |= CSD_WindowFlag_IsConstrainedRight; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: flags |= WindowFlag_IsConstrainedTop; break; case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: flags |= CSD_WindowFlag_IsConstrainedTop; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: flags |= WindowFlag_IsConstrainedBottom; break; case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: flags |= CSD_WindowFlag_IsConstrainedBottom; break;
default: break; default: break;
} }
} }
@ -662,7 +671,7 @@ csd_window_flags_from_states_array(struct wl_array *states){
/* os */ /* os */
static int static int
os_resize_anonymous_file(int fd, off_t size){ csd_os_resize_anonymous_file(int fd, off_t size){
#ifdef HAVE_POSIX_FALLOCATE #ifdef HAVE_POSIX_FALLOCATE
sigset_t mask; sigset_t mask;
@ -699,7 +708,7 @@ os_resize_anonymous_file(int fd, off_t size){
} }
static int static int
os_create_anonymous_file(off_t size){ csd_os_create_anonymous_file(off_t size){
static const char key[] = "/libdecor-shared-XXXXXX"; static const char key[] = "/libdecor-shared-XXXXXX";
int fd = -1; int fd = -1;
@ -750,7 +759,7 @@ os_create_anonymous_file(off_t size){
} }
} }
if (fd >= 0 && os_resize_anonymous_file(fd, size) < 0){ if (fd >= 0 && csd_os_resize_anonymous_file(fd, size) < 0){
close(fd); close(fd);
fd = -1; fd = -1;
} }
@ -760,9 +769,9 @@ os_create_anonymous_file(off_t size){
/* desktop settings */ /* desktop settings */
static CursorTheme static CSD_CursorTheme
ds__get_cursor_theme_from_env(void){ csd_desktop_get_cursor_theme_from_env(void){
CursorTheme result = {0}; CSD_CursorTheme result = {0};
char *env_xtheme = getenv("XCURSOR_THEME"); char *env_xtheme = getenv("XCURSOR_THEME");
char *env_xsize = getenv("XCURSOR_SIZE"); char *env_xsize = getenv("XCURSOR_SIZE");
if (env_xtheme != 0 && env_xsize != 0){ if (env_xtheme != 0 && env_xsize != 0){
@ -780,7 +789,7 @@ ds__get_cursor_theme_from_env(void){
#include <dbus/dbus.h> #include <dbus/dbus.h>
static DBusMessage * static DBusMessage *
ds__get_setting_sync(DBusConnection *const connection, const char *key1, const char *key2){ csd_desktop__get_setting_sync(DBusConnection *const connection, const char *key1, const char *key2){
DBusMessage *reply = 0; DBusMessage *reply = 0;
DBusMessage *message = DBusMessage *message =
dbus_message_new_method_call("org.freedesktop.portal.Desktop", dbus_message_new_method_call("org.freedesktop.portal.Desktop",
@ -810,7 +819,7 @@ ds__get_setting_sync(DBusConnection *const connection, const char *key1, const c
} }
static int static int
ds__parse_type(DBusMessage *const reply, const int type, void *value){ csd_desktop__parse_type(DBusMessage *const reply, const int type, void *value){
int result = 0; int result = 0;
DBusMessageIter iter[3]; DBusMessageIter iter[3];
dbus_message_iter_init(reply, &iter[0]); dbus_message_iter_init(reply, &iter[0]);
@ -827,8 +836,8 @@ ds__parse_type(DBusMessage *const reply, const int type, void *value){
return(result); return(result);
} }
static CursorTheme static CSD_CursorTheme
ds_get_cursor_theme(void){ csd_desktop_get_cursor_theme(void){
static const char key[] = "org.gnome.desktop.interface"; static const char key[] = "org.gnome.desktop.interface";
static const char key_theme[] = "cursor-theme"; static const char key_theme[] = "cursor-theme";
static const char key_size[] = "cursor-size"; static const char key_size[] = "cursor-size";
@ -842,9 +851,9 @@ ds_get_cursor_theme(void){
DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, &error); DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (!dbus_error_is_set(&error)){ if (!dbus_error_is_set(&error)){
DBusMessage *reply = ds__get_setting_sync(connection, key, key_theme); DBusMessage *reply = csd_desktop__get_setting_sync(connection, key, key_theme);
if (reply != 0){ if (reply != 0){
if (!ds__parse_type(reply, DBUS_TYPE_STRING, &name)){ if (!csd_desktop__parse_type(reply, DBUS_TYPE_STRING, &name)){
name = 0; name = 0;
} }
dbus_message_unref(reply); dbus_message_unref(reply);
@ -852,29 +861,29 @@ ds_get_cursor_theme(void){
} }
if (name != 0){ if (name != 0){
DBusMessage *reply = ds__get_setting_sync(connection, key, key_size); DBusMessage *reply = csd_desktop__get_setting_sync(connection, key, key_size);
if (reply){ if (reply){
if (ds__parse_type(reply, DBUS_TYPE_INT32, &size)){ if (csd_desktop__parse_type(reply, DBUS_TYPE_INT32, &size)){
success = 1; success = 1;
} }
dbus_message_unref(reply); dbus_message_unref(reply);
} }
} }
CursorTheme result = {0}; CSD_CursorTheme result = {0};
if (success){ if (success){
result.name = name; result.name = name;
result.size = size; result.size = size;
} }
else{ else{
result = ds__get_cursor_theme_from_env(); result = csd_desktop_get_cursor_theme_from_env();
} }
return(result); return(result);
} }
static ColorScheme static CSD_ColorScheme
ds_get_color_scheme(){ csd_desktop_get_color_scheme(){
static const char name[] = "org.freedesktop.appearance"; static const char name[] = "org.freedesktop.appearance";
static const char key_color_scheme[] = "color-scheme"; static const char key_color_scheme[] = "color-scheme";
uint32_t color = 0; uint32_t color = 0;
@ -884,9 +893,9 @@ ds_get_color_scheme(){
DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, &error); DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (!dbus_error_is_set(&error)){ if (!dbus_error_is_set(&error)){
DBusMessage *reply = ds__get_setting_sync(connection, name, key_color_scheme); DBusMessage *reply = csd_desktop__get_setting_sync(connection, name, key_color_scheme);
if (reply){ if (reply){
if (!ds__parse_type(reply, DBUS_TYPE_UINT32, &color)) { if (!csd_desktop__parse_type(reply, DBUS_TYPE_UINT32, &color)) {
color = 0; color = 0;
} }
dbus_message_unref(reply); dbus_message_unref(reply);
@ -897,14 +906,14 @@ ds_get_color_scheme(){
#else #else
static CursorTheme static CSD_CursorTheme
ds_get_cursor_them(void){ csd_desktop_get_cursor_theme(void){
return(ds__get_cursor_theme_from_env()); return(csd_desktop_get_cursor_theme_from_env());
} }
static ColorScheme static CSD_ColorScheme
ds_get_color_scheme(){ csd_desktop_get_color_scheme(){
return(ColorScheme_Default); return(CSD_ColorScheme_Default);
} }
#endif #endif
@ -921,7 +930,7 @@ csd_gtk_init(void){
g_object_set(gtk_settings_get_default(), g_object_set(gtk_settings_get_default(),
"gtk-application-prefer-dark-theme", "gtk-application-prefer-dark-theme",
(ctx.color_scheme == ColorScheme_Dark), (ctx.color_scheme == CSD_ColorScheme_Dark),
NULL); NULL);
{ {
@ -936,7 +945,7 @@ csd_gtk_init(void){
cairo_fill(cr); cairo_fill(cr);
cairo_destroy(cr); cairo_destroy(cr);
cr_blur_surface(shadow_blur, 64); csd_gtk_blur_surface(shadow_blur, 64);
ctx.gtk_ctx.shadow_blur = shadow_blur; ctx.gtk_ctx.shadow_blur = shadow_blur;
} }
} }
@ -969,7 +978,7 @@ static CSD_Frame
csd_gtk_calculate_frame(void){ csd_gtk_calculate_frame(void){
GTK_Window *gtk_window = &ctx.gtk_window; GTK_Window *gtk_window = &ctx.gtk_window;
CSD_Frame frame = {0}; CSD_Frame frame = {0};
bool show_title = (!(ctx.config.flags & WindowFlag_IsFullscreen)); bool show_title = (!(ctx.config.flags & CSD_WindowFlag_IsFullscreen));
if (show_title){ if (show_title){
gtk_widget_get_preferred_height(gtk_window->header, 0, &frame.border[1][0]); gtk_widget_get_preferred_height(gtk_window->header, 0, &frame.border[1][0]);
gtk_header_bar_set_title(GTK_HEADER_BAR(gtk_window->header), ""); gtk_header_bar_set_title(GTK_HEADER_BAR(gtk_window->header), "");
@ -1014,11 +1023,11 @@ static void
csd_gtk_update_and_render(void){ csd_gtk_update_and_render(void){
GTK_Window *gtk_window = &ctx.gtk_window; GTK_Window *gtk_window = &ctx.gtk_window;
if (ctx.control_flags & WindowControlFlag_Resize){ if (ctx.control_flags & CSD_WindowControlFlag_Resize){
static const CursorShape cursor_box[] = { static const CSD_CursorShape cursor_box[] = {
CursorShape_Resize_TopLeft, CursorShape_Resize_Top, CursorShape_Resize_TopRight, CSD_CursorShape_Resize_TopLeft, CSD_CursorShape_Resize_Top, CSD_CursorShape_Resize_TopRight,
CursorShape_Resize_Left, CursorShape_Pointer, CursorShape_Resize_Right, CSD_CursorShape_Resize_Left, CSD_CursorShape_Pointer, CSD_CursorShape_Resize_Right,
CursorShape_Resize_BottomLeft, CursorShape_Resize_Bottom, CursorShape_Resize_BottomRight, CSD_CursorShape_Resize_BottomLeft, CSD_CursorShape_Resize_Bottom, CSD_CursorShape_Resize_BottomRight,
}; };
static const enum xdg_toplevel_resize_edge xedge_box[] = { static const enum xdg_toplevel_resize_edge xedge_box[] = {
@ -1064,10 +1073,12 @@ csd_gtk_update_and_render(void){
cairo_t *cr = cairo_create(surface); cairo_t *cr = cairo_create(surface);
cairo_surface_set_device_scale(surface, 1, 1); cairo_surface_set_device_scale(surface, 1, 1);
cr_render_shadow(cr, ctx.gtk_ctx.shadow_blur, csd_gtk_render_shadow(cr, ctx.gtk_ctx.shadow_blur,
-(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2,
shadow_dim[0] + SHADOW_MARGIN, shadow_dim[1] + SHADOW_MARGIN, -(int)SHADOW_MARGIN/2,
64, 64); shadow_dim[0] + SHADOW_MARGIN,
shadow_dim[1] + SHADOW_MARGIN,
64, 64);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_rectangle(cr, cairo_rectangle(cr,
SHADOW_MARGIN, SHADOW_MARGIN + ctx.csd_frame.border[1][0], SHADOW_MARGIN, SHADOW_MARGIN + ctx.csd_frame.border[1][0],
@ -1094,9 +1105,9 @@ csd_gtk_update_and_render(void){
memset(subsurface->data, 0, subsurface->size); memset(subsurface->data, 0, subsurface->size);
{ {
int is_resizable = ((ctx.control_flags & WindowControlFlag_Resize) != 0); int is_resizable = ((ctx.control_flags & CSD_WindowControlFlag_Resize) != 0);
gtk_window_set_resizable(GTK_WINDOW(gtk_window->window), is_resizable); gtk_window_set_resizable(GTK_WINDOW(gtk_window->window), is_resizable);
if (!(ctx.config.flags & WindowFlag_IsActivated)){ if (!(ctx.config.flags & CSD_WindowFlag_IsActivated)){
gtk_widget_set_state_flags(gtk_window->window, GTK_STATE_FLAG_BACKDROP, true); gtk_widget_set_state_flags(gtk_window->window, GTK_STATE_FLAG_BACKDROP, true);
} }
else{ else{
@ -1106,7 +1117,7 @@ csd_gtk_update_and_render(void){
{ {
GtkStyleContext *style = gtk_widget_get_style_context(gtk_window->window); GtkStyleContext *style = gtk_widget_get_style_context(gtk_window->window);
if (ctx.config.flags & WindowMask_IsAnchored){ if (ctx.config.flags & CSD_WindowMask_IsAnchored){
gtk_style_context_add_class(style, "maximized"); gtk_style_context_add_class(style, "maximized");
} }
else{ else{
@ -1158,16 +1169,16 @@ csd_gtk_update_and_render(void){
/* buttons */ /* buttons */
uint32_t buttons[3] = {0}; uint32_t buttons[3] = {0};
int button_count = 0; int button_count = 0;
if (ctx.control_flags & WindowControlFlag_Min){ if (ctx.control_flags & CSD_WindowControlFlag_Min){
buttons[button_count] = 0; buttons[button_count] = 0;
button_count += 1; button_count += 1;
} }
if ((ctx.control_flags & WindowControlFlag_Max) && if ((ctx.control_flags & CSD_WindowControlFlag_Max) &&
(ctx.control_flags & WindowControlFlag_Resize)){ (ctx.control_flags & CSD_WindowControlFlag_Resize)){
buttons[button_count] = 1; buttons[button_count] = 1;
button_count += 1; button_count += 1;
} }
if (ctx.control_flags & WindowControlFlag_Close){ if (ctx.control_flags & CSD_WindowControlFlag_Close){
buttons[button_count] = 2; buttons[button_count] = 2;
button_count += 1; button_count += 1;
} }
@ -1184,7 +1195,7 @@ csd_gtk_update_and_render(void){
}break; }break;
case 1: { case 1: {
button_name = ".maximize"; button_name = ".maximize";
icon_name = ((ctx.config.flags & WindowFlag_IsMax) ? icon_name = ((ctx.config.flags & CSD_WindowFlag_IsMax) ?
"window-restore-symbolic" : "window-maximize-symbolic"); "window-restore-symbolic" : "window-maximize-symbolic");
}break; }break;
case 2: { case 2: {
@ -1201,7 +1212,7 @@ csd_gtk_update_and_render(void){
/* change style based on window state and focus */ /* change style based on window state and focus */
GtkStateFlags style_state = 0; GtkStateFlags style_state = 0;
if (!(ctx.config.flags & WindowFlag_IsActivated)){ if (!(ctx.config.flags & CSD_WindowFlag_IsActivated)){
style_state |= GTK_STATE_FLAG_BACKDROP; style_state |= GTK_STATE_FLAG_BACKDROP;
} }
if (gtk_window->hover_button_code == button_code){ if (gtk_window->hover_button_code == button_code){
@ -1255,8 +1266,8 @@ csd_gtk_update_and_render(void){
gtk_style_context_get_state(style), gtk_style_context_get_state(style),
"min-width", &width, "min-width", &width,
"min-height", &height, NULL); "min-height", &height, NULL);
width = ClampBot(width, icon_width); width = CSD_ClampBot(width, icon_width);
height = ClampBot(height, icon_height); height = CSD_ClampBot(height, icon_height);
gint left = 0; gint left = 0;
gint top = 0; gint top = 0;
@ -1302,7 +1313,7 @@ csd_gtk_update_and_render(void){
/* cairo shadow rendering */ /* cairo shadow rendering */
static int static int
cr_blur_surface(cairo_surface_t *surface, int margin){ csd_gtk_blur_surface(cairo_surface_t *surface, int margin){
int32_t width, height, stride, x, y, z, w; int32_t width, height, stride, x, y, z, w;
uint8_t *src, *dst; uint8_t *src, *dst;
uint32_t *s, *d, a, p; uint32_t *s, *d, a, p;
@ -1390,9 +1401,9 @@ cr_blur_surface(cairo_surface_t *surface, int margin){
} }
static void static void
cr_render_shadow(cairo_t *cr, cairo_surface_t *surface, csd_gtk_render_shadow(cairo_t *cr, cairo_surface_t *surface,
int x, int y, int width, int height, int x, int y, int width, int height,
int margin, int top_margin){ int margin, int top_margin){
cairo_pattern_t *pattern; cairo_pattern_t *pattern;
cairo_matrix_t matrix; cairo_matrix_t matrix;
int i, fx, fy, shadow_height, shadow_width; int i, fx, fy, shadow_height, shadow_width;
@ -1508,4 +1519,4 @@ cr_render_shadow(cairo_t *cr, cairo_surface_t *surface,
cairo_pattern_destroy(pattern); cairo_pattern_destroy(pattern);
cairo_reset_clip(cr); cairo_reset_clip(cr);
} }

View File

@ -1,83 +1,93 @@
#ifndef WAYLAND_GTK_EGL_EXAMPLE_H #ifndef WAYLAND_GTK_EGL_EXAMPLE_H
#define WAYLAND_GTK_EGL_EXAMPLE_H #define WAYLAND_GTK_EGL_EXAMPLE_H
#define HAS_DBUS /* csd */
#define HAVE_MEMFD_CREATE
#define HAVE_POSIX_FALLOCATE
#define Min(a, b) ((a)>(b)?(b):(a)) typedef uint8_t CSD_U8;
#define Max(a, b) ((a)<(b)?(b):(a)) typedef uint32_t CSD_U32;
typedef uint64_t CSD_U64;
#define ClampTop(x, a) Min(x, a) typedef int8_t CSD_S8;
#define ClampBot(x, a) Max(x, a) typedef int32_t CSD_S32;
typedef enum ColorScheme{ typedef int8_t CSD_B8;
ColorScheme_Default, typedef int32_t CSD_B32;
ColorScheme_Dark,
ColorScheme_Light
} ColorScheme;
typedef struct CursorTheme{ typedef double CSD_F64;
#define CSD_Min(a, b) ((a)>(b)?(b):(a))
#define CSD_Max(a, b) ((a)<(b)?(b):(a))
#define CSD_ClampTop(x, a) CSD_Min(x, a)
#define CSD_ClampBot(x, a) CSD_Max(x, a)
typedef enum CSD_ColorScheme{
CSD_ColorScheme_Default,
CSD_ColorScheme_Dark,
CSD_ColorScheme_Light
} CSD_ColorScheme;
typedef struct CSD_CursorTheme{
char *name; char *name;
int size; int size;
} CursorTheme; } CSD_CursorTheme;
typedef uint32_t CursorShape; typedef uint32_t CSD_CursorShape;
enum{ enum{
CursorShape_Hidden, CSD_CursorShape_Hidden,
CursorShape_Pointer, CSD_CursorShape_Pointer,
CursorShape_Resize_Top, CSD_CursorShape_Resize_Top,
CursorShape_Resize_Bottom, CSD_CursorShape_Resize_Bottom,
CursorShape_Resize_Left, CSD_CursorShape_Resize_Left,
CursorShape_Resize_Right, CSD_CursorShape_Resize_Right,
CursorShape_Resize_TopLeft, CSD_CursorShape_Resize_TopLeft,
CursorShape_Resize_TopRight, CSD_CursorShape_Resize_TopRight,
CursorShape_Resize_BottomLeft, CSD_CursorShape_Resize_BottomLeft,
CursorShape_Resize_BottomRight, CSD_CursorShape_Resize_BottomRight,
CursorShape_COUNT CSD_CursorShape_COUNT
}; };
typedef uint32_t WindowFlags; typedef uint32_t CSD_WindowFlags;
enum{ enum{
WindowFlag_IsFullscreen = (1 << 0), CSD_WindowFlag_IsFullscreen = (1 << 0),
WindowFlag_IsMax = (1 << 1), CSD_WindowFlag_IsMax = (1 << 1),
WindowFlag_IsActivated = (1 << 2), CSD_WindowFlag_IsActivated = (1 << 2),
WindowFlag_IsTiledLeft = (1 << 3), CSD_WindowFlag_IsTiledLeft = (1 << 3),
WindowFlag_IsTiledRight = (1 << 4), CSD_WindowFlag_IsTiledRight = (1 << 4),
WindowFlag_IsTiledTop = (1 << 5), CSD_WindowFlag_IsTiledTop = (1 << 5),
WindowFlag_IsTiledBottom = (1 << 6), CSD_WindowFlag_IsTiledBottom = (1 << 6),
WindowFlag_IsResizing = (1 << 7), CSD_WindowFlag_IsResizing = (1 << 7),
WindowFlag_IsSuspended = (1 << 8), CSD_WindowFlag_IsSuspended = (1 << 8),
WindowFlag_IsConstrainedLeft = (1 << 9), CSD_WindowFlag_IsConstrainedLeft = (1 << 9),
WindowFlag_IsConstrainedRight = (1 << 10), CSD_WindowFlag_IsConstrainedRight = (1 << 10),
WindowFlag_IsConstrainedTop = (1 << 11), CSD_WindowFlag_IsConstrainedTop = (1 << 11),
WindowFlag_IsConstrainedBottom = (1 << 12), CSD_WindowFlag_IsConstrainedBottom = (1 << 12),
}; };
#define WindowMask_IsAnchored \ #define CSD_WindowMask_IsAnchored \
(WindowFlag_IsFullscreen|WindowFlag_IsMax| \ (CSD_WindowFlag_IsFullscreen|CSD_WindowFlag_IsMax| \
WindowFlag_IsTiledLeft |WindowFlag_IsTiledRight| \ CSD_WindowFlag_IsTiledLeft |CSD_WindowFlag_IsTiledRight| \
WindowFlag_IsTiledTop |WindowFlag_IsTiledBottom) CSD_WindowFlag_IsTiledTop |CSD_WindowFlag_IsTiledBottom)
typedef uint32_t WindowControlFlags; typedef uint32_t CSD_WindowControlFlags;
enum{ enum{
WindowControlFlag_Move = (1 << 0), CSD_WindowControlFlag_Move = (1 << 0),
WindowControlFlag_Resize = (1 << 1), CSD_WindowControlFlag_Resize = (1 << 1),
WindowControlFlag_Min = (1 << 2), CSD_WindowControlFlag_Min = (1 << 2),
WindowControlFlag_Max = (1 << 3), CSD_WindowControlFlag_Max = (1 << 3),
WindowControlFlag_Close = (1 << 4), CSD_WindowControlFlag_Close = (1 << 4),
}; };
typedef struct Config{ typedef struct CSD_Config{
uint32_t serial; CSD_U32 serial;
int32_t dim[2]; CSD_S32 dim[2];
WindowFlags flags; CSD_WindowFlags flags;
uint32_t decoration_mode; CSD_U32 decoration_mode;
} Config; } CSD_Config;
typedef struct CSD_Frame{ typedef struct CSD_Frame{
int32_t border[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max CSD_S32 border[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max
int32_t minbox[2]; CSD_S32 minbox[2];
} CSD_Frame; } CSD_Frame;
typedef struct CSD_SubSurface{ typedef struct CSD_SubSurface{
@ -85,19 +95,50 @@ typedef struct CSD_SubSurface{
struct wl_subsurface *wl_subsurface; struct wl_subsurface *wl_subsurface;
struct wl_buffer *wl_buffer; struct wl_buffer *wl_buffer;
void *data; void *data;
uint64_t size; CSD_U64 size;
int32_t dim[2]; CSD_S32 dim[2];
int32_t p[2]; CSD_S32 p[2];
} CSD_SubSurface; } CSD_SubSurface;
typedef struct GTK_Ctx{ /* csd helpers */
cairo_surface_t *shadow_blur;
} GTK_Ctx;
typedef struct GTK_Window{ static CSD_SubSurface csd_subsurface_new(void);
int32_t p[2]; static void csd_subsurface_buffer_clear(CSD_SubSurface *subsurface);
uint32_t button; static void csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, CSD_S32 dim[2]);
int double_click_time_ms; static void csd_subsurface_set_position(CSD_SubSurface *subsurface, CSD_S32 x, CSD_S32 y);
static void csd_subsurface_commit(CSD_SubSurface *subsurface);
static CSD_WindowFlags csd_window_flags_from_states_array(struct wl_array *states);
/* os */
static int csd_os_resize_anonymous_file(int fd, off_t size);
static int csd_os_create_anonymous_file(off_t size);
/* desktop settings */
static CSD_CursorTheme csd_desktop_get_cursor_theme(void);
static CSD_ColorScheme csd_desktop_get_color_scheme(void);
static CSD_CursorTheme csd_desktop_get_cursor_theme_from_env(void);
#if defined(HAS_DBUS)
#include <dbus/dbus.h>
static DBusMessage* csd_desktop__get_setting_sync(DBusConnection *const connection, const char *k, const char *v);
static int csd_desktop__parse_type(DBusMessage *const reply, const int type, void *value);
#endif /* defined(HAS_DBUS) */
/* csd gtk */
typedef struct CSD_GTK_Ctx{
cairo_surface_t *shadow_blur;
} CSD_GTK_Ctx;
typedef struct CSD_GTK_Window{
CSD_S32 p[2];
CSD_U32 button;
CSD_S32 double_click_time_ms;
CSD_SubSurface titlebar; CSD_SubSurface titlebar;
CSD_SubSurface shadow; CSD_SubSurface shadow;
@ -105,17 +146,36 @@ typedef struct GTK_Window{
GtkWidget *window; GtkWidget *window;
GtkWidget *header; GtkWidget *header;
uint32_t hover_button_code; CSD_U32 hover_button_code;
uint32_t active_button_code; CSD_U32 active_button_code;
} GTK_Window; } GTK_Window;
/* csd gtk implementation */
static void csd_gtk_init(void);
static void csd_gtk_window_init(void);
static CSD_Frame csd_gtk_calculate_frame(void);
static void csd_gtk_update_and_render(void);
static void csd_gtk_render(void);
/* csd gtk cairo shadow rendering */
static int csd_gtk_blur_surface(cairo_surface_t *surface, int margin);
static void csd_gtk_render_shadow(cairo_t *cr, cairo_surface_t *surface,
int x, int y, int width, int height,
int margin, int top_margin);
/* example */
typedef struct Ctx{ typedef struct Ctx{
/* "application variables" */ /* "application variables" */
int close_signal; CSD_B32 close_signal;
/* globals: desktop settings */ /* globals: desktop settings */
ColorScheme color_scheme; CSD_ColorScheme color_scheme;
CursorTheme cursor_theme; CSD_CursorTheme cursor_theme;
/* globals: wayland */ /* globals: wayland */
struct wl_display *wl_display; struct wl_display *wl_display;
@ -127,14 +187,14 @@ typedef struct Ctx{
struct zxdg_decoration_manager_v1 *zxdg_decoration_manager; struct zxdg_decoration_manager_v1 *zxdg_decoration_manager;
struct wl_cursor_theme *wl_cursor_theme; struct wl_cursor_theme *wl_cursor_theme;
struct wl_cursor *wl_cursors[CursorShape_COUNT]; struct wl_cursor *wl_cursors[CSD_CursorShape_COUNT];
/* globals: egl */ /* globals: egl */
EGLDisplay egl_display; EGLDisplay egl_display;
EGLContext egl_context; EGLContext egl_context;
/* globals: gtk */ /* globals: gtk */
GTK_Ctx gtk_ctx; CSD_GTK_Ctx gtk_ctx;
/* per-seat: wayland */ /* per-seat: wayland */
struct wl_seat *wl_seat; struct wl_seat *wl_seat;
@ -143,7 +203,7 @@ typedef struct Ctx{
struct wl_surface *hover_surface; struct wl_surface *hover_surface;
CursorShape cursor_shape; CSD_CursorShape cursor_shape;
/* per-window: wayland */ /* per-window: wayland */
struct wl_surface *main_wl_surface; struct wl_surface *main_wl_surface;
@ -156,65 +216,19 @@ typedef struct Ctx{
EGLSurface main_egl_surface; EGLSurface main_egl_surface;
/* per-window */ /* per-window */
WindowControlFlags control_flags; CSD_WindowControlFlags control_flags;
int32_t dim[2]; int32_t dim[2];
int32_t mmbox[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max int32_t mmbox[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max
Config config; CSD_Config config;
Config config_staged; CSD_Config config_staged;
uint32_t serial; CSD_U32 serial;
int handled_first_size; CSD_B32 handled_first_size;
CSD_Frame csd_frame; CSD_Frame csd_frame;
int32_t csd_dim[2]; CSD_S32 csd_dim[2];
GTK_Window gtk_window; GTK_Window gtk_window;
} Ctx; } Ctx;
/* csd helpers */
static CSD_SubSurface csd_subsurface_new(void);
static void csd_subsurface_buffer_clear(CSD_SubSurface *subsurface);
static void csd_subsurface_buffer_alloc(CSD_SubSurface *subsurface, int32_t dim[2]);
static void csd_subsurface_set_position(CSD_SubSurface *subsurface, int32_t x, int32_t y);
static void csd_subsurface_commit(CSD_SubSurface *subsurface);
static WindowFlags csd_window_flags_from_states_array(struct wl_array *states);
/* os */
static int os_resize_anonymous_file(int fd, off_t size);
static int os_create_anonymous_file(off_t size);
/* desktop settings */
static CursorTheme ds_get_cursor_theme(void);
static ColorScheme ds_get_color_scheme(void);
static CursorTheme ds__get_cursor_theme_from_env(void);
#if defined(HAS_DBUS)
#include <dbus/dbus.h>
static DBusMessage* ds__get_setting_sync(DBusConnection *const connection, const char *k, const char *v);
static int ds__parse_type(DBusMessage *const reply, const int type, void *value);
#endif /* defined(HAS_DBUS) */
/* csd gtk implementation */
static void csd_gtk_init(void);
static void csd_gtk_window_init(void);
static CSD_Frame csd_gtk_calculate_frame(void);
static void csd_gtk_update_and_render(void);
static void csd_gtk_render(void);
/* cairo shadow rendering */
static int cr_blur_surface(cairo_surface_t *surface, int margin);
static void cr_render_shadow(cairo_t *cr, cairo_surface_t *surface,
int x, int y, int width, int height,
int margin, int top_margin);
#endif /* WAYLAND_GTK_EGL_EXAMPLE_H */ #endif /* WAYLAND_GTK_EGL_EXAMPLE_H */