From 6aa7fb12b4a2e4ddc415960df60be8643d79894d Mon Sep 17 00:00:00 2001 From: hkc Date: Tue, 9 Apr 2024 17:29:48 +0300 Subject: [PATCH] X11+SDL2 -> xcb+cairo --- Makefile | 4 +- src/cairo_context.c | 47 ++++++++++++ src/cairo_context.h | 22 ++++++ src/main.c | 26 +++---- src/rootwindow.c | 170 +++++++++++++++++++------------------------- src/rootwindow.h | 4 +- src/sdl_xroot.c | 40 ----------- src/sdl_xroot.h | 17 ----- 8 files changed, 158 insertions(+), 172 deletions(-) create mode 100644 src/cairo_context.c create mode 100644 src/cairo_context.h delete mode 100644 src/sdl_xroot.c delete mode 100644 src/sdl_xroot.h diff --git a/Makefile b/Makefile index 4b9b223..a7d7a6b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS += -LDFLAGS := -lm -lX11 -lSDL2 -lSDL2_image -OBJECTS := obj/rootwindow.o obj/sdl_xroot.o +LDFLAGS := -lm -lcairo -lxcb +OBJECTS := obj/rootwindow.o obj/cairo_context.o livewp: lib $(CC) $(CFLAGS) $(OBJECTS) src/main.c $(LDFLAGS) -o livewp diff --git a/src/cairo_context.c b/src/cairo_context.c new file mode 100644 index 0000000..3e0babf --- /dev/null +++ b/src/cairo_context.c @@ -0,0 +1,47 @@ +#include "cairo_context.h" +#include "rootwindow.h" +#include +#include +#include + +bool cairo_ctx_create(const char *display, struct cairo_ctx *ctx) { + if (!(ctx->connection = xcb_connect(display, NULL))) return false; + + // grab first screen + ctx->screen = xcb_setup_roots_iterator(xcb_get_setup(ctx->connection)).data; + + for ( + xcb_depth_iterator_t iter_depth = xcb_screen_allowed_depths_iterator(ctx->screen); + iter_depth.rem; + xcb_depth_next(&iter_depth)) { + int visual_length = xcb_depth_visuals_length(iter_depth.data); + xcb_visualtype_t *visual = xcb_depth_visuals(iter_depth.data); + for (int i = 0; i < visual_length; i++) { + if (visual->visual_id == ctx->screen->root_visual) { + ctx->visual = visual; + break; + } + } + } + + ctx->wid = create_root_window(ctx->connection, ctx->screen); + + ctx->surface = cairo_xcb_surface_create(ctx->connection, ctx->wid, ctx->visual, ctx->screen->width_in_pixels, ctx->screen->height_in_pixels); + ctx->cairo = cairo_create(ctx->surface); + + return true; +} + +void cairo_begin(struct cairo_ctx *ctx) { + xcb_clear_area(ctx->connection, 0, ctx->wid, 0, 0, 0, 0); +} + +void cairo_flush(struct cairo_ctx *ctx) { + xcb_flush(ctx->connection); +} + +void cairo_ctx_close(struct cairo_ctx *ctx) { + cairo_destroy(ctx->cairo); + xcb_destroy_window(ctx->connection, ctx->wid); + xcb_disconnect(ctx->connection); +} diff --git a/src/cairo_context.h b/src/cairo_context.h new file mode 100644 index 0000000..03548ac --- /dev/null +++ b/src/cairo_context.h @@ -0,0 +1,22 @@ +#ifndef _CAIRO_CONTEXT_H_ +#define _CAIRO_CONTEXT_H_ + +#include +#include +#include + +struct cairo_ctx { + cairo_t *cairo; + cairo_surface_t *surface; + xcb_connection_t *connection; + xcb_screen_t *screen; + xcb_window_t wid; + xcb_visualtype_t *visual; +}; + +bool cairo_ctx_create(const char *display, struct cairo_ctx *ctx); +void cairo_begin(struct cairo_ctx *ctx); +void cairo_flush(struct cairo_ctx *ctx); +void cairo_ctx_close(struct cairo_ctx *ctx); + +#endif diff --git a/src/main.c b/src/main.c index b32efe8..56e23b0 100644 --- a/src/main.c +++ b/src/main.c @@ -1,20 +1,17 @@ -#include #include #include #include #include #include -#include "sdl_xroot.h" +#include "cairo_context.h" -struct sdlxroot_context ctx; -SDL_Renderer *renderer; +struct cairo_ctx ctx; volatile bool running = true; void cleanup(void) { - SDL_DestroyRenderer(renderer); - sdlxroot_close(&ctx); + cairo_ctx_close(&ctx); } void sighandler(int sig) { @@ -22,7 +19,7 @@ void sighandler(int sig) { } int main(void) { - if (!sdlxroot_create(NULL, &ctx)) { + if (!cairo_ctx_create(NULL, &ctx)) { fprintf(stderr, "Failed creating window or something\n"); return EXIT_FAILURE; } @@ -30,14 +27,13 @@ int main(void) { atexit(cleanup); signal(SIGINT, sighandler); - renderer = SDL_CreateRenderer(ctx.window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - - while (running) { - SDL_SetRenderDrawColor(renderer, 0x13, 0x13, 0x13, 0); - SDL_RenderClear(renderer); - SDL_SetRenderDrawColor(renderer, 0xff, 0x00, 0x00, 0xff); - SDL_RenderDrawLine(renderer, 200, 200, 600, 600); - SDL_RenderPresent(renderer); + for (float t = 0.0; running; t += 1.0 / 60.0) { + cairo_begin(&ctx); + { + cairo_set_source_rgb(ctx.cairo, 0.0, 0.5 - sin(t) * 0.5, 0.5 - cos(t) * 0.5); + cairo_paint(ctx.cairo); + } + cairo_flush(&ctx); usleep(1000); } diff --git a/src/rootwindow.c b/src/rootwindow.c index 0940299..90e0539 100644 --- a/src/rootwindow.c +++ b/src/rootwindow.c @@ -1,119 +1,97 @@ #include "rootwindow.h" -#include -#include -#include #include +#include +#include #include +#include #include +#include -#define ATOM(a) XInternAtom(display, #a, False) -Window find_desktop_window(Display *display, int screen, Window *ptr_root, Window *ptr_desktop); -Window find_subwindow(Display *display, Window win, int w, int h, int dw, int dh); +xcb_window_t find_subwindow(xcb_connection_t *connection, xcb_window_t win, int w, int h); -Window create_root_window(Display *display, int screen) { - // below, sticky, fullscreen, skip_taskbar, skip_pager, noFocus, override, - // set_desktop_type +xcb_window_t create_root_window(xcb_connection_t *connection, xcb_screen_t *screen) { + xcb_window_t root = find_subwindow(connection, screen->root, -1, -1); + if (!root) return 0; - XSetWindowAttributes attrs = { - ParentRelative, 0L, 0, 0L, 0, 0, Always, 0L, 0L, False, StructureNotifyMask | ExposureMask, 0L, True, 0, 0 - }; + xcb_window_t parent = find_subwindow(connection, root, screen->width_in_pixels, screen->height_in_pixels); + if (!parent) return 0; - int screen_w = DisplayWidth(display, screen), - screen_h = DisplayHeight(display, screen); + xcb_window_t wid = xcb_generate_id(connection); - Window root, desktop; - if (!find_desktop_window(display, screen, &root, &desktop)) { - fprintf(stderr, "find_desktop_window() failed\n"); - return 0; + { + uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_BACKING_STORE | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; + uint32_t values[] = { + screen->white_pixel, + XCB_BACKING_STORE_ALWAYS, + 1, + XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE + }; + + xcb_create_window( + connection, + XCB_COPY_FROM_PARENT, + wid, + parent, + 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + screen->root_visual, + mask, values); } - Window window = XCreateWindow(display, desktop, 0, 0, screen_w, screen_h, 0, CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect | CWBackingStore, &attrs); - if (!window) { - fprintf(stderr, "XCreateWindow() failed: %s\n", strerror(errno)); + { + const static uint32_t values[] = { XCB_STACK_MODE_BELOW }; + xcb_configure_window(connection, wid, XCB_CONFIG_WINDOW_STACK_MODE, values); } - XLowerWindow(display, window); - XMapWindow(display, window); - XSync(display, window); - return window; + + xcb_map_window(connection, wid); + xcb_flush(connection); + + return wid; } -// from xwinwrap -Window find_subwindow(Display *display, Window win, int w, int h, int dw, int dh) { - unsigned int i, j; - Window troot, parent, *children; - unsigned int n; - /* search subwindows with same size as display or work area */ +bool get_window_attributes(xcb_connection_t *connection, xcb_window_t wid, xcb_get_window_attributes_reply_t *out) { + xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(connection, wid); + xcb_get_window_attributes_reply_t *reply = xcb_get_window_attributes_reply(connection, cookie, 0); + if (!reply) return false; + memcpy(out, reply, sizeof(xcb_get_window_attributes_reply_t)); + free(reply); + return true; +} - for (i = 0; i < 10; i++) { - XQueryTree(display, win, &troot, &parent, &children, &n); +bool get_window_geometry(xcb_connection_t *connection, xcb_window_t wid, xcb_rectangle_t *rect) { + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(connection, wid); + xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(connection, cookie, 0); + if (!reply) return false; - for (j = 0; j < n; j++) { - XWindowAttributes attrs; + rect->x = reply->x; + rect->y = reply->y; + rect->width = reply->width; + rect->height = reply->height; - if (XGetWindowAttributes(display, children[j], &attrs)) { - /* Window must be mapped and same size as display or - * work space */ - if (attrs.map_state != 0 && - ((attrs.width == dw && attrs.height == dh) || - (attrs.width == w && attrs.height == h))) { - win = children[j]; - break; - } + free(reply); + return true; +} + + +xcb_window_t find_subwindow(xcb_connection_t *connection, xcb_window_t win, int w, int h) { + xcb_query_tree_reply_t *qt_reply; + xcb_query_tree_cookie_t qt_cookie = xcb_query_tree(connection, win); + + if ((qt_reply = xcb_query_tree_reply(connection, qt_cookie, 0))) { + xcb_window_t *children = xcb_query_tree_children(qt_reply); + xcb_rectangle_t rect; + xcb_get_window_attributes_reply_t attrs; + for (int i = 0; i < xcb_query_tree_children_length(qt_reply); i++) { + if (!get_window_geometry(connection, children[i], &rect)) continue; + if (!get_window_attributes(connection, children[i], &attrs)) continue; + + if (attrs.map_state != 0 && rect.width == w && rect.height == h) { + free(qt_reply); + return children[i]; } } - - XFree(children); - if (j == n) { - break; - } + free(qt_reply); } - return win; } - -Window find_desktop_window(Display *display, int screen, Window *ptr_root, Window *ptr_desktop) { - int display_width, display_height; - Atom type; - int format; - unsigned long n_items, n_bytes; - unsigned char *buf = NULL; - Window root = RootWindow(display, screen); - - Window win = root; - Window tmp_root, parent, *children; - unsigned int n_windows; - - XQueryTree(display, root, &tmp_root, &parent, &children, &n_windows); - for (int i = 0; i < (int)n_windows; i++) { - if (XGetWindowProperty(display, children[i], ATOM(__SWM_VROOT), 0, 1, False, XA_WINDOW, &type, &format, &n_items, &n_bytes, &buf) == Success && type == XA_WINDOW) { - win = *(Window *)buf; - XFree(buf); - XFree(children); - *ptr_root = win; - *ptr_desktop = win; - return win; - } - - if (buf) { - XFree(buf); - buf = NULL; - } - } - XFree(children); - - win = find_subwindow(display, root, -1, -1, display_width, display_height); - display_width = DisplayWidth(display, screen); - display_height = DisplayHeight(display, screen); - win = find_subwindow(display, win, display_width, display_height, display_width, display_height); - - if (buf) { - XFree(buf); - buf = NULL; - } - - *ptr_root = root; - *ptr_desktop = win; - return win; -} - diff --git a/src/rootwindow.h b/src/rootwindow.h index f24000e..4566ae6 100644 --- a/src/rootwindow.h +++ b/src/rootwindow.h @@ -1,8 +1,8 @@ #ifndef _ROOTWINDOW_H_ #define _ROOTWINDOW_H_ -#include +#include -Window create_root_window(Display *display, int screen); +xcb_window_t create_root_window(xcb_connection_t *connection, xcb_screen_t *screen); #endif diff --git a/src/sdl_xroot.c b/src/sdl_xroot.c deleted file mode 100644 index f3301ea..0000000 --- a/src/sdl_xroot.c +++ /dev/null @@ -1,40 +0,0 @@ - -#include "sdl_xroot.h" -#include "rootwindow.h" -#include -#include -#include - -bool sdlxroot_create(const char *display_name, struct sdlxroot_context *ctx) { - Display *display = XOpenDisplay(display_name); - if (!display) return false; - - SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); - - // TODO: error handling - // FIXME: what is the invalid value for `Window`? -1? 0? some other value? - // docs aren't clear about it, or i'm just blind - - ctx->x11_screen = DefaultScreen(display); - Window root_window = create_root_window(display, ctx->x11_screen); - if (!root_window) { - XCloseDisplay(display); - fprintf(stderr, "create_root_window() failed\n"); - return false; - } - - ctx->x11_display = display; - ctx->x11_window = root_window; - - ctx->window = SDL_CreateWindowFrom((void *)ctx->x11_window); - if (!ctx->window) { - fprintf(stderr, "SDL_CreateWindowFrom(0x%08lx) failed\n", ctx->x11_window); - } - return ctx->window != NULL; -} - -void sdlxroot_close(struct sdlxroot_context *ctx) { - SDL_DestroyWindow(ctx->window); - XDestroyWindow((Display *)ctx->x11_display, (Window)ctx->x11_window); - XCloseDisplay((Display *)ctx->x11_display); -} diff --git a/src/sdl_xroot.h b/src/sdl_xroot.h deleted file mode 100644 index 6a032e4..0000000 --- a/src/sdl_xroot.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _SDL_XROOT_H_ -#define _SDL_XROOT_H_ - -#include -#include - -struct sdlxroot_context { - SDL_Window *window; - void *x11_display; - unsigned long x11_window; - int x11_screen; -}; - -bool sdlxroot_create(const char *display_name, struct sdlxroot_context *ctx); -void sdlxroot_close(struct sdlxroot_context *ctx); - -#endif