linux-windowing/wayland_egl.c

800 lines
23 KiB
C
Executable File

#if 0
libdecor_path="/home/mr4th/mr4th/libdecor"
root_path="$PWD"
dbus_flags="$(pkg-config --cflags --libs dbus-1)"
my_flags="-Iwayland -I$libdecor_path/src -I$libdecor_path/src/plugins -I$libdecor_path/build"
my_flags+=" -lwayland-client -lwayland-cursor -lwayland-egl -lEGL -lm"
mkdir -p build
clang -o build/demo -g $root_path/wayland_egl.c $dbus_flags $my_flags
exit 0
#endif
#define _GNU_SOURCE
#include <wayland-client.h>
#include <wayland-client-core.h>
#include <wayland-cursor.h>
#include <wayland-egl.h>
/*~ NOTE: wayland-egl.h *before* EGL/ */
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/glcorearb.h>
#include <errno.h>
#include <dirent.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <poll.h>
#include <math.h>
#include <linux/input.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xdg-shell-client-protocol.h"
#include "xdg-decoration-client-protocol.h"
#include "xdg-shell-client-protocol.c"
#include "xdg-decoration-client-protocol.c"
#include "wayland_egl.h"
// X(N:name,R:return,P:params)
#define GL_FUNCS_XLIST(X)\
X(glDrawBuffer, void, (GLenum buf)) \
X(glViewport, void, (GLint x, GLint y, GLsizei w, GLsizei h)) \
X(glClear, void, (GLbitfield mask)) \
X(glClearColor, void, (GLfloat r, GLfloat g, GLfloat b, GLfloat a))
#define X(N,R,P) R (*N)P = 0;
GL_FUNCS_XLIST(X)
#undef X
static Ctx ctx = {0};
static void
shm_format(void *udata, struct wl_shm *wl_shm, uint32_t format){
}
const struct wl_shm_listener shm_listener = {
shm_format
};
static void
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 = {
xdg_wm_base_ping
};
static void
pointer_enter(void *udata, struct wl_pointer *wl_pointer, uint32_t serial,
struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y){
}
static void
pointer_leave(void *udata, struct wl_pointer *wl_pointer, uint32_t serial,
struct wl_surface *surface){
}
static void
pointer_motion(void *udata, struct wl_pointer *wl_pointer, uint32_t time,
wl_fixed_t surface_x, wl_fixed_t surface_y){
}
static void
pointer_button(void *udata, struct wl_pointer *wl_pointer, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state){
}
static void
pointer_axis(void *udata, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value){
}
const struct wl_pointer_listener pointer_listener = {
pointer_enter,
pointer_leave,
pointer_motion,
pointer_button,
pointer_axis
};
static void
seat_capabilities(void *udata, struct wl_seat *wl_seat, uint32_t capabilities){
if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && ctx.wl_pointer == 0){
ctx.wl_pointer = wl_seat_get_pointer(ctx.wl_seat);
wl_pointer_add_listener(ctx.wl_pointer, &pointer_listener, 0);
}
else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && ctx.wl_pointer != 0){
wl_pointer_release(ctx.wl_pointer);
ctx.wl_pointer = 0;
}
}
static void
seat_name(void *udata, struct wl_seat *wl_seat, const char *name){
}
const struct wl_seat_listener seat_listener = {
seat_capabilities,
seat_name
};
static void
registry_global(void *udata, struct wl_registry *wl_registry,
uint32_t name, const char *interface,
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));
}
else if (strcmp(interface, "wl_subcompositor") == 0){
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));
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));
}
else if (strcmp(interface, "wl_seat") == 0){
ctx.wl_seat = wl_registry_bind(ctx.wl_registry, name, &wl_seat_interface, 3);
wl_seat_add_listener(ctx.wl_seat, &seat_listener, 0);
ctx.cursor_surface = wl_compositor_create_surface(ctx.wl_compositor);
}
}
static void
registry_global_remove(void *udata, struct wl_registry *registry,
uint32_t name){
}
const struct wl_registry_listener registry_listener = {
registry_global,
registry_global_remove,
};
static void
xdg_surface_configure(void *udata, struct xdg_surface *xdg_surface,
uint32_t serial){
ctx.config_staged.serial = serial;
}
const struct xdg_surface_listener xdg_surface_listener = { xdg_surface_configure, };
static void
xdg_toplevel_configure(void *udata, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height, struct wl_array *states){
if (width != 0 && height != 0){
ctx.config_staged.dim[0] = width;
ctx.config_staged.dim[1] = height;
}
else{
ctx.config_staged.dim[0] = ctx.config.dim[0];
ctx.config_staged.dim[1] = ctx.config.dim[1];
}
ctx.config_staged.flags = window_flags_from_states_array(states);
}
static void
xdg_toplevel_close(void *udata, struct xdg_toplevel *xdg_toplevel){
ctx.close_signal = 1;
}
static void
xdg_toplevel_configure_bounds(void *udata, struct xdg_toplevel *xdg_toplevel,
int32_t w, int32_t h){
}
static void
xdg_toplevel_wm_capabilities(void *udata, struct xdg_toplevel *xdg_toplevel,
struct wl_array *capabilities){
}
const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_configure,
xdg_toplevel_close,
xdg_toplevel_configure_bounds,
xdg_toplevel_wm_capabilities,
};
static void
xdg_toplevel_decoration_configure(void *udata, struct zxdg_toplevel_decoration_v1 *toplevel,
uint32_t mode){
ctx.config_staged.decoration_mode = mode;
}
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();
/* setup Wayland */
{
ctx.wl_display = wl_display_connect(0);
ctx.wl_registry = wl_display_get_registry(ctx.wl_display);
wl_registry_add_listener(ctx.wl_registry, &registry_listener, 0);
wl_display_flush(ctx.wl_display);
wl_display_dispatch(ctx.wl_display);
ctx.wl_cursor_theme = wl_cursor_theme_load(ctx.cursor_theme.name,
ctx.cursor_theme.size,
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");
#undef X
}
/* setup EGL */
{
ctx.egl_display = eglGetDisplay(ctx.wl_display);
EGLint major = 0, minor = 0;
eglInitialize(ctx.egl_display, &major, &minor);
eglBindAPI(EGL_OPENGL_API);
{
EGLint attr[] = {
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_CONTEXT_MINOR_VERSION, 3,
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_NONE,
};
ctx.egl_context = eglCreateContext(ctx.egl_display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attr);
}
eglMakeCurrent(ctx.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx.egl_context);
#define X(N,R,P) N = (R(*)P)(eglGetProcAddress(#N));
GL_FUNCS_XLIST(X)
#undef X
}
/* create a window */
{
/* window main surface */
ctx.main_wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
ctx.main_xdg_surface = xdg_wm_base_get_xdg_surface(ctx.xdg_wm_base, ctx.main_wl_surface);
xdg_surface_add_listener(ctx.main_xdg_surface, &xdg_surface_listener, 0);
ctx.main_xdg_toplevel = xdg_surface_get_toplevel(ctx.main_xdg_surface);
xdg_toplevel_add_listener(ctx.main_xdg_toplevel, &xdg_toplevel_listener, 0);
ctx.config.dim[0] = 640;
ctx.config.dim[1] = 480;
ctx.control_flags = ~0;
ctx.config_staged.decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
if (ctx.zxdg_decoration_manager != 0){
ctx.main_zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(ctx.zxdg_decoration_manager, ctx.main_xdg_toplevel);
zxdg_toplevel_decoration_v1_add_listener(ctx.main_zxdg_toplevel_decoration, &zxdg_toplevel_decoration_listener, 0);
}
for (int k = 0; k < 2; k += 1){
ctx.mmbox[k][0] = 0;
ctx.mmbox[k][1] = (1 << 30);
}
xdg_toplevel_set_app_id(ctx.main_xdg_toplevel, "demo");
xdg_toplevel_set_title(ctx.main_xdg_toplevel, "Example Window");
wl_surface_commit(ctx.main_wl_surface);
/* window subsurface */
ctx.shadow_wl_surface = wl_compositor_create_surface(ctx.wl_compositor);
ctx.shadow_wl_subsurface =
wl_subcompositor_get_subsurface(ctx.wl_subcompositor,
ctx.shadow_wl_surface,
ctx.main_wl_surface);
{
int dim[2] = {640, 25};
int stride = 4*dim[0];
uint64_t size = 4*dim[0]*dim[1];
int fd = 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){
struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size);
struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, 0, dim[0], dim[1], stride,
WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
ctx.shadow_wl_buffer = wl_buffer;
ctx.shadow_data = data;
ctx.shadow_size = size;
for (int i = 0; i < 2; i += 1){
ctx.shadow_dim[i] = dim[i];
}
}
close(fd);
}
}
/* window egl */
ctx.main_wl_egl_window = wl_egl_window_create(ctx.main_wl_surface,
ctx.config.dim[0],
ctx.config.dim[1]);
EGLConfig configs[64];
EGLint config_cap = sizeof(configs)/sizeof(*configs);
EGLint config_count = 0;
{
EGLint attributes[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_CONFORMANT, EGL_OPENGL_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_NONE,
};
eglChooseConfig(ctx.egl_display, attributes, configs, config_cap, &config_count);
}
{
EGLint attributes[] = {
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
EGL_NONE,
};
for (EGLint i = 0; i < config_count; i += 1){
ctx.main_egl_surface = eglCreateWindowSurface(ctx.egl_display, configs[i], ctx.main_wl_egl_window, attributes);
if (ctx.main_egl_surface != EGL_NO_SURFACE){
break;
}
}
}
eglMakeCurrent(ctx.egl_display, ctx.main_egl_surface,
ctx.main_egl_surface, ctx.egl_context);
eglSwapInterval(ctx.egl_display, 1);
}
/* main loop */
int exit_loop = 0;
for (;!exit_loop;){
/* poll for events */
{
struct pollfd fds[1] = {0};
/* register fds[0] ~ wayland events */
bool wayland_started_read = false;
bool wayland_did_read = false;
{
fds[0].fd = -1;
wl_display_dispatch_pending(ctx.wl_display);
wayland_started_read = (wl_display_prepare_read(ctx.wl_display) != -1);
if (wayland_started_read){
fds[0].fd = wl_display_get_fd(ctx.wl_display);
fds[0].events = POLLIN;
wl_display_flush(ctx.wl_display);
}
}
/* poll and handle events */
int ret = poll(fds, sizeof(fds)/sizeof(*fds), 0);
if (ret > 0){
/* handle fds[0] ~ wayland events */
if (fds[0].revents & POLLIN){
wayland_did_read = true;
wl_display_read_events(ctx.wl_display);
wl_display_dispatch_pending(ctx.wl_display);
}
}
/* wayland event read cleanup */
if (wayland_started_read && !wayland_did_read){
wl_display_cancel_read(ctx.wl_display);
}
}
/* apply config */
if (ctx.config.serial != ctx.config_staged.serial){
ctx.config = ctx.config_staged;
xdg_surface_ack_configure(ctx.main_xdg_surface, ctx.config.serial);
}
int csd = (ctx.config.decoration_mode ==
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
/* window sizing */
CSD_Frame csd_frame = {0};
int32_t csd_dim[2];
{
if (csd){
csd_frame = csd_impl_calculate_frame();
}
for (int i = 0; i < 2; i += 1){
csd_dim[i] = csd_frame.border[i][0] + csd_frame.border[i][1];
int32_t d = ctx.config.dim[i] - csd_dim[i];
d = ClampBot(d, ctx.mmbox[i][0]);
d = ClampTop(d, ctx.mmbox[i][1]);
d = ClampBot(d, csd_frame.minbox[i]);
ctx.dim[i] = d;
}
}
/* window frame render */
if (csd){
uint32_t *pxl = (uint32_t*)ctx.shadow_data;
for (int32_t y = 0; y < ctx.shadow_dim[1]; y += 1){
for (int32_t x = 0; x < ctx.shadow_dim[0]; x += 1){
*pxl = 0xFFFF0000;
pxl += 1;
}
}
}
/* window frame commit */
if (csd){
{
wl_surface_attach(ctx.shadow_wl_surface, ctx.shadow_wl_buffer, 0, 0);
wl_surface_set_buffer_scale(ctx.shadow_wl_surface, 1);
wl_surface_damage_buffer(ctx.shadow_wl_surface, 0, 0,
ctx.shadow_dim[0], ctx.shadow_dim[1]);
wl_subsurface_set_position(ctx.shadow_wl_subsurface, 0, -25);
wl_surface_commit(ctx.shadow_wl_surface);
}
if (!(ctx.control_flags & 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], csd_frame.minbox[i]) + csd_dim[0];
int32_t mh = ctx.mmbox[1][i] + csd_dim[1];
if (i == 0){
xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, mw, mh);
}
else{
xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, mw, mh);
}
}
}
}
/* app update & render */
{
if (ctx.close_signal){
exit_loop = 1;
}
glDrawBuffer(GL_BACK);
glViewport(0, 0, ctx.config.dim[0], ctx.config.dim[1]);
glClearColor(0.40f, 0.90f, 0.15f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
eglSwapBuffers(ctx.egl_display, ctx.main_egl_surface);
wl_surface_commit(ctx.main_wl_surface);
}
return(0);
}
/* csd implementation */
static CSD_Frame
csd_impl_calculate_frame(void){
CSD_Frame frame = {0};
bool show_title = (!(ctx.config.flags & WindowFlag_IsFullscreen));
if (show_title){
frame.border[1][0] = 25;
}
return(frame);
}
/* wayland helpers */
static WindowFlags
window_flags_from_states_array(struct wl_array *states){
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;
default: break;
}
}
return(flags);
}
/* os */
static int
os_resize_anonymous_file(int fd, off_t size){
#ifdef HAVE_POSIX_FALLOCATE
sigset_t mask;
sigset_t old_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, &old_mask);
do {
errno = posix_fallocate(fd, 0, size);
} while (errno == EINTR);
sigprocmask(SIG_SETMASK, &old_mask, NULL);
int result = 0;
if (errno != 0){
result = -1;
if (errno == EINVAL || errno == EOPNOTSUPP){
if (ftruncate(fd, size) >= 0){
result = 0;
}
}
}
return(result);
#else
int result = -1;
if (ftruncate(fd, size) >= 0){
result = 0;
}
return(result);
#endif
}
static int
os_create_anonymous_file(off_t size){
static const char key[] = "/libdecor-shared-XXXXXX";
int fd = -1;
#ifdef HAVE_MEMFD_CREATE
fd = memfd_create("libdecor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd >= 0){
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
}
#endif
if (fd < 0){
const char *path = getenv("XDG_RUNTIME_DIR");
if (path == 0){
errno = ENOENT;
}
else{
char *name = malloc(strlen(path) + sizeof(key));
if (name != 0){
strcpy(name, path);
strcat(name, key);
#ifdef HAVE_MKOSTEMP
fd = mkostemp(name, O_CLOEXEC);
if (fd >= 0){
unlink(name);
}
#else
fd = mkstemp(name);
if (fd >= 0){
if (fcntl(fd, F_GETFD) == -1){
close(fd);
fd = -1;
}
else if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1){
close(fd);
fd = -1;
}
}
if (fd >= 0) {
unlink(name);
}
#endif
free(name);
}
}
}
if (fd >= 0 && os_resize_anonymous_file(fd, size) < 0){
close(fd);
fd = -1;
}
return(fd);
}
/* desktop settings */
static CursorTheme
ds__get_cursor_theme_from_env(void){
CursorTheme result = {0};
char *env_xtheme = getenv("XCURSOR_THEME");
char *env_xsize = getenv("XCURSOR_SIZE");
if (env_xtheme != 0 && env_xsize != 0){
result.name = strdup(env_xtheme);
result.size = atoi(env_xsize);
}
else{
result.name = 0;
result.size = 24;
}
return(result);
}
#ifdef HAS_DBUS
#include <dbus/dbus.h>
static DBusMessage *
ds__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",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
"Read");
if (message != 0){
dbus_bool_t success = dbus_message_append_args(message,
DBUS_TYPE_STRING, &key1,
DBUS_TYPE_STRING, &key2,
DBUS_TYPE_INVALID);
if (success){
DBusError error;
dbus_error_init(&error);
reply = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error);
if (dbus_error_is_set(&error) && reply != 0){
dbus_message_unref(reply);
reply = 0;
}
dbus_error_free(&error);
}
dbus_message_unref(message);
}
return(reply);
}
static int
ds__parse_type(DBusMessage *const reply, const int type, void *value){
int result = 0;
DBusMessageIter iter[3];
dbus_message_iter_init(reply, &iter[0]);
if (dbus_message_iter_get_arg_type(&iter[0]) == DBUS_TYPE_VARIANT){
dbus_message_iter_recurse(&iter[0], &iter[1]);
if (dbus_message_iter_get_arg_type(&iter[1]) == DBUS_TYPE_VARIANT){
dbus_message_iter_recurse(&iter[1], &iter[2]);
if (dbus_message_iter_get_arg_type(&iter[2]) == type){
dbus_message_iter_get_basic(&iter[2], value);
result = 1;
}
}
}
return(result);
}
static CursorTheme
ds_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";
char *name = 0;
int size = 0;
int success = 0;
DBusError error;
dbus_error_init(&error);
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);
if (reply != 0){
if (!ds__parse_type(reply, DBUS_TYPE_STRING, &name)){
name = 0;
}
dbus_message_unref(reply);
}
}
if (name != 0){
DBusMessage *reply = ds__get_setting_sync(connection, key, key_size);
if (reply){
if (ds__parse_type(reply, DBUS_TYPE_INT32, &size)){
success = 1;
}
dbus_message_unref(reply);
}
}
CursorTheme result = {0};
if (success){
result.name = name;
result.size = size;
}
else{
result = ds__get_cursor_theme_from_env();
}
return(result);
}
static ColorScheme
ds_get_color_scheme(){
static const char name[] = "org.freedesktop.appearance";
static const char key_color_scheme[] = "color-scheme";
uint32_t color = 0;
DBusError error;
dbus_error_init(&error);
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);
if (reply){
if (!ds__parse_type(reply, DBUS_TYPE_UINT32, &color)) {
color = 0;
}
dbus_message_unref(reply);
}
}
return(color);
}
#else
static CursorTheme
ds_get_cursor_them(void){
return(ds__get_cursor_theme_from_env());
}
static ColorScheme
ds_get_color_scheme(){
return(ColorScheme_Default);
}
#endif