[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 HAS_DBUS
#define HAVE_MKOSTEMP
#define HAVE_MEMFD_CREATE
#define HAVE_POSIX_FALLOCATE
#include <wayland-client.h>
#include <wayland-client-core.h>
#include <wayland-cursor.h>
#include <wayland-egl.h>
/*~ NOTE: wayland-egl.h *before* EGL/ */
/*~ NOTE: wayland-egl.h *before* EGL includes */
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/glcorearb.h>
@ -62,10 +67,9 @@ GL_FUNCS_XLIST(X)
static Ctx ctx = {0};
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
};
@ -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);
}
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
};
@ -173,7 +177,7 @@ pointer_axis(void *udata, struct wl_pointer *wl_pointer,
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_leave,
pointer_motion,
@ -194,10 +198,9 @@ seat_capabilities(void *udata, struct wl_seat *wl_seat, uint32_t capabilities){
}
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_name
};
@ -208,21 +211,28 @@ registry_global(void *udata, struct wl_registry *wl_registry,
uint32_t version){
if (strcmp(interface, "wl_compositor") == 0){
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){
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){
ctx.wl_shm = wl_registry_bind(ctx.wl_registry, name, &wl_shm_interface, 1);
wl_shm_add_listener(ctx.wl_shm, &shm_listener, 0);
}
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);
}
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){
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
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_remove,
};
@ -247,7 +256,9 @@ xdg_surface_configure(void *udata, struct xdg_surface *xdg_surface,
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
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
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
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_close,
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;
}
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
};
int main(){
/* desktop settings */
ctx.color_scheme = ds_get_color_scheme();
ctx.cursor_theme = ds_get_cursor_theme();
ctx.color_scheme = csd_desktop_get_color_scheme();
ctx.cursor_theme = csd_desktop_get_cursor_theme();
/* setup gtk */
csd_gtk_init();
@ -317,15 +327,15 @@ int main(){
ctx.wl_shm);
#define X(k,n) ctx.wl_cursors[k] = wl_cursor_theme_get_cursor(ctx.wl_cursor_theme, n);
X(CursorShape_Pointer, "left_ptr");
X(CursorShape_Resize_Top, "top_side");
X(CursorShape_Resize_Bottom, "bottom_side");
X(CursorShape_Resize_Left, "left_side");
X(CursorShape_Resize_Right, "right_side");
X(CursorShape_Resize_TopLeft, "top_left_corner");
X(CursorShape_Resize_BottomLeft, "bottom_left_corner");
X(CursorShape_Resize_TopRight, "top_right_corner");
X(CursorShape_Resize_BottomRight, "bottom_right_corner");
X(CSD_CursorShape_Pointer, "left_ptr");
X(CSD_CursorShape_Resize_Top, "top_side");
X(CSD_CursorShape_Resize_Bottom, "bottom_side");
X(CSD_CursorShape_Resize_Left, "left_side");
X(CSD_CursorShape_Resize_Right, "right_side");
X(CSD_CursorShape_Resize_TopLeft, "top_left_corner");
X(CSD_CursorShape_Resize_BottomLeft, "bottom_left_corner");
X(CSD_CursorShape_Resize_TopRight, "top_right_corner");
X(CSD_CursorShape_Resize_BottomRight, "bottom_right_corner");
#undef X
}
@ -495,21 +505,21 @@ int main(){
d = ctx.dim[i];
ctx.config.dim[i] = d + ctx.csd_dim[i];
}
d = ClampBot(d, ctx.mmbox[i][0]);
d = ClampTop(d, ctx.mmbox[i][1]);
d = ClampBot(d, ctx.csd_frame.minbox[i]);
d = CSD_ClampBot(d, ctx.mmbox[i][0]);
d = CSD_ClampTop(d, ctx.mmbox[i][1]);
d = CSD_ClampBot(d, ctx.csd_frame.minbox[i]);
ctx.dim[i] = d;
}
ctx.handled_first_size = 1;
/* 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_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]);
}
else{
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];
if (i == 0){
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);
/* frame update and render */
ctx.cursor_shape = CursorShape_Pointer;
ctx.cursor_shape = CSD_CursorShape_Pointer;
csd_gtk_update_and_render();
/* app update & render */
@ -573,8 +583,7 @@ csd_subsurface_new(void){
CSD_SubSurface result = {0};
result.wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
result.wl_subsurface =
wl_subcompositor_get_subsurface(ctx.wl_subcompositor,
result.wl_surface,
wl_subcompositor_get_subsurface(ctx.wl_subcompositor, result.wl_surface,
ctx.main_wl_surface);
return(result);
}
@ -592,11 +601,11 @@ csd_subsurface_buffer_clear(CSD_SubSurface *subsurface){
}
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];
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){
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data != MAP_FAILED){
@ -619,7 +628,7 @@ 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){
csd_subsurface_set_position(CSD_SubSurface *subsurface, CSD_S32 x, CSD_S32 y){
wl_subsurface_set_position(subsurface->wl_subsurface, x, y);
subsurface->p[0] = x;
subsurface->p[1] = y;
@ -634,25 +643,25 @@ csd_subsurface_commit(CSD_SubSurface *subsurface){
wl_surface_commit(subsurface->wl_surface);
}
static WindowFlags
static CSD_WindowFlags
csd_window_flags_from_states_array(struct wl_array *states){
WindowFlags flags = 0;
CSD_WindowFlags flags = 0;
uint32_t *p;
wl_array_for_each(p, states){
switch (*p) {
case XDG_TOPLEVEL_STATE_FULLSCREEN: flags |= WindowFlag_IsFullscreen; break;
case XDG_TOPLEVEL_STATE_MAXIMIZED: flags |= WindowFlag_IsMax; break;
case XDG_TOPLEVEL_STATE_ACTIVATED: flags |= WindowFlag_IsActivated; break;
case XDG_TOPLEVEL_STATE_TILED_LEFT: flags |= WindowFlag_IsTiledLeft; break;
case XDG_TOPLEVEL_STATE_TILED_RIGHT: flags |= WindowFlag_IsTiledRight; break;
case XDG_TOPLEVEL_STATE_TILED_TOP: flags |= WindowFlag_IsTiledTop; break;
case XDG_TOPLEVEL_STATE_TILED_BOTTOM: flags |= WindowFlag_IsTiledBottom; break;
case XDG_TOPLEVEL_STATE_RESIZING: flags |= WindowFlag_IsResizing; break;
case XDG_TOPLEVEL_STATE_SUSPENDED: flags |= WindowFlag_IsSuspended; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: flags |= WindowFlag_IsConstrainedLeft; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: flags |= WindowFlag_IsConstrainedRight; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: flags |= WindowFlag_IsConstrainedTop; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: flags |= WindowFlag_IsConstrainedBottom; break;
case XDG_TOPLEVEL_STATE_FULLSCREEN: flags |= CSD_WindowFlag_IsFullscreen; break;
case XDG_TOPLEVEL_STATE_MAXIMIZED: flags |= CSD_WindowFlag_IsMax; break;
case XDG_TOPLEVEL_STATE_ACTIVATED: flags |= CSD_WindowFlag_IsActivated; break;
case XDG_TOPLEVEL_STATE_TILED_LEFT: flags |= CSD_WindowFlag_IsTiledLeft; break;
case XDG_TOPLEVEL_STATE_TILED_RIGHT: flags |= CSD_WindowFlag_IsTiledRight; break;
case XDG_TOPLEVEL_STATE_TILED_TOP: flags |= CSD_WindowFlag_IsTiledTop; break;
case XDG_TOPLEVEL_STATE_TILED_BOTTOM: flags |= CSD_WindowFlag_IsTiledBottom; break;
case XDG_TOPLEVEL_STATE_RESIZING: flags |= CSD_WindowFlag_IsResizing; break;
case XDG_TOPLEVEL_STATE_SUSPENDED: flags |= CSD_WindowFlag_IsSuspended; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_LEFT: flags |= CSD_WindowFlag_IsConstrainedLeft; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_RIGHT: flags |= CSD_WindowFlag_IsConstrainedRight; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_TOP: flags |= CSD_WindowFlag_IsConstrainedTop; break;
case XDG_TOPLEVEL_STATE_CONSTRAINED_BOTTOM: flags |= CSD_WindowFlag_IsConstrainedBottom; break;
default: break;
}
}
@ -662,7 +671,7 @@ csd_window_flags_from_states_array(struct wl_array *states){
/* os */
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
sigset_t mask;
@ -699,7 +708,7 @@ os_resize_anonymous_file(int fd, off_t size){
}
static int
os_create_anonymous_file(off_t size){
csd_os_create_anonymous_file(off_t size){
static const char key[] = "/libdecor-shared-XXXXXX";
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);
fd = -1;
}
@ -760,9 +769,9 @@ os_create_anonymous_file(off_t size){
/* desktop settings */
static CursorTheme
ds__get_cursor_theme_from_env(void){
CursorTheme result = {0};
static CSD_CursorTheme
csd_desktop_get_cursor_theme_from_env(void){
CSD_CursorTheme result = {0};
char *env_xtheme = getenv("XCURSOR_THEME");
char *env_xsize = getenv("XCURSOR_SIZE");
if (env_xtheme != 0 && env_xsize != 0){
@ -780,7 +789,7 @@ ds__get_cursor_theme_from_env(void){
#include <dbus/dbus.h>
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 *message =
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
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;
DBusMessageIter iter[3];
dbus_message_iter_init(reply, &iter[0]);
@ -827,8 +836,8 @@ ds__parse_type(DBusMessage *const reply, const int type, void *value){
return(result);
}
static CursorTheme
ds_get_cursor_theme(void){
static CSD_CursorTheme
csd_desktop_get_cursor_theme(void){
static const char key[] = "org.gnome.desktop.interface";
static const char key_theme[] = "cursor-theme";
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);
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 (!ds__parse_type(reply, DBUS_TYPE_STRING, &name)){
if (!csd_desktop__parse_type(reply, DBUS_TYPE_STRING, &name)){
name = 0;
}
dbus_message_unref(reply);
@ -852,29 +861,29 @@ ds_get_cursor_theme(void){
}
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 (ds__parse_type(reply, DBUS_TYPE_INT32, &size)){
if (csd_desktop__parse_type(reply, DBUS_TYPE_INT32, &size)){
success = 1;
}
dbus_message_unref(reply);
}
}
CursorTheme result = {0};
CSD_CursorTheme result = {0};
if (success){
result.name = name;
result.size = size;
}
else{
result = ds__get_cursor_theme_from_env();
result = csd_desktop_get_cursor_theme_from_env();
}
return(result);
}
static ColorScheme
ds_get_color_scheme(){
static CSD_ColorScheme
csd_desktop_get_color_scheme(){
static const char name[] = "org.freedesktop.appearance";
static const char key_color_scheme[] = "color-scheme";
uint32_t color = 0;
@ -884,9 +893,9 @@ ds_get_color_scheme(){
DBusConnection *connection = dbus_bus_get(DBUS_BUS_SESSION, &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 (!ds__parse_type(reply, DBUS_TYPE_UINT32, &color)) {
if (!csd_desktop__parse_type(reply, DBUS_TYPE_UINT32, &color)) {
color = 0;
}
dbus_message_unref(reply);
@ -897,14 +906,14 @@ ds_get_color_scheme(){
#else
static CursorTheme
ds_get_cursor_them(void){
return(ds__get_cursor_theme_from_env());
static CSD_CursorTheme
csd_desktop_get_cursor_theme(void){
return(csd_desktop_get_cursor_theme_from_env());
}
static ColorScheme
ds_get_color_scheme(){
return(ColorScheme_Default);
static CSD_ColorScheme
csd_desktop_get_color_scheme(){
return(CSD_ColorScheme_Default);
}
#endif
@ -921,7 +930,7 @@ csd_gtk_init(void){
g_object_set(gtk_settings_get_default(),
"gtk-application-prefer-dark-theme",
(ctx.color_scheme == ColorScheme_Dark),
(ctx.color_scheme == CSD_ColorScheme_Dark),
NULL);
{
@ -936,7 +945,7 @@ csd_gtk_init(void){
cairo_fill(cr);
cairo_destroy(cr);
cr_blur_surface(shadow_blur, 64);
csd_gtk_blur_surface(shadow_blur, 64);
ctx.gtk_ctx.shadow_blur = shadow_blur;
}
}
@ -969,7 +978,7 @@ static CSD_Frame
csd_gtk_calculate_frame(void){
GTK_Window *gtk_window = &ctx.gtk_window;
CSD_Frame frame = {0};
bool show_title = (!(ctx.config.flags & WindowFlag_IsFullscreen));
bool show_title = (!(ctx.config.flags & CSD_WindowFlag_IsFullscreen));
if (show_title){
gtk_widget_get_preferred_height(gtk_window->header, 0, &frame.border[1][0]);
gtk_header_bar_set_title(GTK_HEADER_BAR(gtk_window->header), "");
@ -1014,11 +1023,11 @@ static void
csd_gtk_update_and_render(void){
GTK_Window *gtk_window = &ctx.gtk_window;
if (ctx.control_flags & WindowControlFlag_Resize){
static const CursorShape cursor_box[] = {
CursorShape_Resize_TopLeft, CursorShape_Resize_Top, CursorShape_Resize_TopRight,
CursorShape_Resize_Left, CursorShape_Pointer, CursorShape_Resize_Right,
CursorShape_Resize_BottomLeft, CursorShape_Resize_Bottom, CursorShape_Resize_BottomRight,
if (ctx.control_flags & CSD_WindowControlFlag_Resize){
static const CSD_CursorShape cursor_box[] = {
CSD_CursorShape_Resize_TopLeft, CSD_CursorShape_Resize_Top, CSD_CursorShape_Resize_TopRight,
CSD_CursorShape_Resize_Left, CSD_CursorShape_Pointer, CSD_CursorShape_Resize_Right,
CSD_CursorShape_Resize_BottomLeft, CSD_CursorShape_Resize_Bottom, CSD_CursorShape_Resize_BottomRight,
};
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_surface_set_device_scale(surface, 1, 1);
cr_render_shadow(cr, ctx.gtk_ctx.shadow_blur,
-(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2,
shadow_dim[0] + SHADOW_MARGIN, shadow_dim[1] + SHADOW_MARGIN,
64, 64);
csd_gtk_render_shadow(cr, ctx.gtk_ctx.shadow_blur,
-(int)SHADOW_MARGIN/2,
-(int)SHADOW_MARGIN/2,
shadow_dim[0] + SHADOW_MARGIN,
shadow_dim[1] + SHADOW_MARGIN,
64, 64);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_rectangle(cr,
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);
{
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);
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);
}
else{
@ -1106,7 +1117,7 @@ csd_gtk_update_and_render(void){
{
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");
}
else{
@ -1158,16 +1169,16 @@ csd_gtk_update_and_render(void){
/* buttons */
uint32_t buttons[3] = {0};
int button_count = 0;
if (ctx.control_flags & WindowControlFlag_Min){
if (ctx.control_flags & CSD_WindowControlFlag_Min){
buttons[button_count] = 0;
button_count += 1;
}
if ((ctx.control_flags & WindowControlFlag_Max) &&
(ctx.control_flags & WindowControlFlag_Resize)){
if ((ctx.control_flags & CSD_WindowControlFlag_Max) &&
(ctx.control_flags & CSD_WindowControlFlag_Resize)){
buttons[button_count] = 1;
button_count += 1;
}
if (ctx.control_flags & WindowControlFlag_Close){
if (ctx.control_flags & CSD_WindowControlFlag_Close){
buttons[button_count] = 2;
button_count += 1;
}
@ -1184,7 +1195,7 @@ csd_gtk_update_and_render(void){
}break;
case 1: {
button_name = ".maximize";
icon_name = ((ctx.config.flags & WindowFlag_IsMax) ?
icon_name = ((ctx.config.flags & CSD_WindowFlag_IsMax) ?
"window-restore-symbolic" : "window-maximize-symbolic");
}break;
case 2: {
@ -1201,7 +1212,7 @@ csd_gtk_update_and_render(void){
/* change style based on window state and focus */
GtkStateFlags style_state = 0;
if (!(ctx.config.flags & WindowFlag_IsActivated)){
if (!(ctx.config.flags & CSD_WindowFlag_IsActivated)){
style_state |= GTK_STATE_FLAG_BACKDROP;
}
if (gtk_window->hover_button_code == button_code){
@ -1255,8 +1266,8 @@ csd_gtk_update_and_render(void){
gtk_style_context_get_state(style),
"min-width", &width,
"min-height", &height, NULL);
width = ClampBot(width, icon_width);
height = ClampBot(height, icon_height);
width = CSD_ClampBot(width, icon_width);
height = CSD_ClampBot(height, icon_height);
gint left = 0;
gint top = 0;
@ -1302,7 +1313,7 @@ csd_gtk_update_and_render(void){
/* cairo shadow rendering */
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;
uint8_t *src, *dst;
uint32_t *s, *d, a, p;
@ -1390,9 +1401,9 @@ 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){
csd_gtk_render_shadow(cairo_t *cr, cairo_surface_t *surface,
int x, int y, int width, int height,
int margin, int top_margin){
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
int i, fx, fy, shadow_height, shadow_width;

View File

@ -1,83 +1,93 @@
#ifndef WAYLAND_GTK_EGL_EXAMPLE_H
#define WAYLAND_GTK_EGL_EXAMPLE_H
#define HAS_DBUS
#define HAVE_MEMFD_CREATE
#define HAVE_POSIX_FALLOCATE
/* csd */
#define Min(a, b) ((a)>(b)?(b):(a))
#define Max(a, b) ((a)<(b)?(b):(a))
typedef uint8_t CSD_U8;
typedef uint32_t CSD_U32;
typedef uint64_t CSD_U64;
#define ClampTop(x, a) Min(x, a)
#define ClampBot(x, a) Max(x, a)
typedef int8_t CSD_S8;
typedef int32_t CSD_S32;
typedef enum ColorScheme{
ColorScheme_Default,
ColorScheme_Dark,
ColorScheme_Light
} ColorScheme;
typedef int8_t CSD_B8;
typedef int32_t CSD_B32;
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;
int size;
} CursorTheme;
} CSD_CursorTheme;
typedef uint32_t CursorShape;
typedef uint32_t CSD_CursorShape;
enum{
CursorShape_Hidden,
CursorShape_Pointer,
CursorShape_Resize_Top,
CursorShape_Resize_Bottom,
CursorShape_Resize_Left,
CursorShape_Resize_Right,
CursorShape_Resize_TopLeft,
CursorShape_Resize_TopRight,
CursorShape_Resize_BottomLeft,
CursorShape_Resize_BottomRight,
CursorShape_COUNT
CSD_CursorShape_Hidden,
CSD_CursorShape_Pointer,
CSD_CursorShape_Resize_Top,
CSD_CursorShape_Resize_Bottom,
CSD_CursorShape_Resize_Left,
CSD_CursorShape_Resize_Right,
CSD_CursorShape_Resize_TopLeft,
CSD_CursorShape_Resize_TopRight,
CSD_CursorShape_Resize_BottomLeft,
CSD_CursorShape_Resize_BottomRight,
CSD_CursorShape_COUNT
};
typedef uint32_t WindowFlags;
typedef uint32_t CSD_WindowFlags;
enum{
WindowFlag_IsFullscreen = (1 << 0),
WindowFlag_IsMax = (1 << 1),
WindowFlag_IsActivated = (1 << 2),
WindowFlag_IsTiledLeft = (1 << 3),
WindowFlag_IsTiledRight = (1 << 4),
WindowFlag_IsTiledTop = (1 << 5),
WindowFlag_IsTiledBottom = (1 << 6),
WindowFlag_IsResizing = (1 << 7),
WindowFlag_IsSuspended = (1 << 8),
WindowFlag_IsConstrainedLeft = (1 << 9),
WindowFlag_IsConstrainedRight = (1 << 10),
WindowFlag_IsConstrainedTop = (1 << 11),
WindowFlag_IsConstrainedBottom = (1 << 12),
CSD_WindowFlag_IsFullscreen = (1 << 0),
CSD_WindowFlag_IsMax = (1 << 1),
CSD_WindowFlag_IsActivated = (1 << 2),
CSD_WindowFlag_IsTiledLeft = (1 << 3),
CSD_WindowFlag_IsTiledRight = (1 << 4),
CSD_WindowFlag_IsTiledTop = (1 << 5),
CSD_WindowFlag_IsTiledBottom = (1 << 6),
CSD_WindowFlag_IsResizing = (1 << 7),
CSD_WindowFlag_IsSuspended = (1 << 8),
CSD_WindowFlag_IsConstrainedLeft = (1 << 9),
CSD_WindowFlag_IsConstrainedRight = (1 << 10),
CSD_WindowFlag_IsConstrainedTop = (1 << 11),
CSD_WindowFlag_IsConstrainedBottom = (1 << 12),
};
#define WindowMask_IsAnchored \
(WindowFlag_IsFullscreen|WindowFlag_IsMax| \
WindowFlag_IsTiledLeft |WindowFlag_IsTiledRight| \
WindowFlag_IsTiledTop |WindowFlag_IsTiledBottom)
#define CSD_WindowMask_IsAnchored \
(CSD_WindowFlag_IsFullscreen|CSD_WindowFlag_IsMax| \
CSD_WindowFlag_IsTiledLeft |CSD_WindowFlag_IsTiledRight| \
CSD_WindowFlag_IsTiledTop |CSD_WindowFlag_IsTiledBottom)
typedef uint32_t WindowControlFlags;
typedef uint32_t CSD_WindowControlFlags;
enum{
WindowControlFlag_Move = (1 << 0),
WindowControlFlag_Resize = (1 << 1),
WindowControlFlag_Min = (1 << 2),
WindowControlFlag_Max = (1 << 3),
WindowControlFlag_Close = (1 << 4),
CSD_WindowControlFlag_Move = (1 << 0),
CSD_WindowControlFlag_Resize = (1 << 1),
CSD_WindowControlFlag_Min = (1 << 2),
CSD_WindowControlFlag_Max = (1 << 3),
CSD_WindowControlFlag_Close = (1 << 4),
};
typedef struct Config{
uint32_t serial;
int32_t dim[2];
WindowFlags flags;
uint32_t decoration_mode;
} Config;
typedef struct CSD_Config{
CSD_U32 serial;
CSD_S32 dim[2];
CSD_WindowFlags flags;
CSD_U32 decoration_mode;
} CSD_Config;
typedef struct CSD_Frame{
int32_t border[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max
int32_t minbox[2];
CSD_S32 border[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max
CSD_S32 minbox[2];
} CSD_Frame;
typedef struct CSD_SubSurface{
@ -85,19 +95,50 @@ typedef struct CSD_SubSurface{
struct wl_subsurface *wl_subsurface;
struct wl_buffer *wl_buffer;
void *data;
uint64_t size;
int32_t dim[2];
int32_t p[2];
CSD_U64 size;
CSD_S32 dim[2];
CSD_S32 p[2];
} CSD_SubSurface;
typedef struct GTK_Ctx{
cairo_surface_t *shadow_blur;
} GTK_Ctx;
/* csd helpers */
typedef struct GTK_Window{
int32_t p[2];
uint32_t button;
int double_click_time_ms;
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, CSD_S32 dim[2]);
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 shadow;
@ -105,17 +146,36 @@ typedef struct GTK_Window{
GtkWidget *window;
GtkWidget *header;
uint32_t hover_button_code;
uint32_t active_button_code;
CSD_U32 hover_button_code;
CSD_U32 active_button_code;
} 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{
/* "application variables" */
int close_signal;
CSD_B32 close_signal;
/* globals: desktop settings */
ColorScheme color_scheme;
CursorTheme cursor_theme;
CSD_ColorScheme color_scheme;
CSD_CursorTheme cursor_theme;
/* globals: wayland */
struct wl_display *wl_display;
@ -127,14 +187,14 @@ typedef struct Ctx{
struct zxdg_decoration_manager_v1 *zxdg_decoration_manager;
struct wl_cursor_theme *wl_cursor_theme;
struct wl_cursor *wl_cursors[CursorShape_COUNT];
struct wl_cursor *wl_cursors[CSD_CursorShape_COUNT];
/* globals: egl */
EGLDisplay egl_display;
EGLContext egl_context;
/* globals: gtk */
GTK_Ctx gtk_ctx;
CSD_GTK_Ctx gtk_ctx;
/* per-seat: wayland */
struct wl_seat *wl_seat;
@ -143,7 +203,7 @@ typedef struct Ctx{
struct wl_surface *hover_surface;
CursorShape cursor_shape;
CSD_CursorShape cursor_shape;
/* per-window: wayland */
struct wl_surface *main_wl_surface;
@ -156,65 +216,19 @@ typedef struct Ctx{
EGLSurface main_egl_surface;
/* per-window */
WindowControlFlags control_flags;
CSD_WindowControlFlags control_flags;
int32_t dim[2];
int32_t mmbox[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max
Config config;
Config config_staged;
uint32_t serial;
CSD_Config config;
CSD_Config config_staged;
CSD_U32 serial;
int handled_first_size;
CSD_B32 handled_first_size;
CSD_Frame csd_frame;
int32_t csd_dim[2];
CSD_S32 csd_dim[2];
GTK_Window gtk_window;
} 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 */