diff --git a/Makefile b/Makefile index 953e2b9..4b9b223 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ CFLAGS += -LDFLAGS := -lm -OBJECTS := +LDFLAGS := -lm -lX11 -lSDL2 -lSDL2_image +OBJECTS := obj/rootwindow.o obj/sdl_xroot.o livewp: lib $(CC) $(CFLAGS) $(OBJECTS) src/main.c $(LDFLAGS) -o livewp +testrun: all + ./livewp + all: livewp lib: $(OBJECTS) diff --git a/example.lua b/example.lua new file mode 100644 index 0000000..a42eff3 --- /dev/null +++ b/example.lua @@ -0,0 +1,37 @@ + +local img = assert(image_load("/home/hkc/images/wallpapers/wallpaper.png")) +local font = assert(font_load("/usr/share/fonts/TTF/TerminusTTF.ttf")) + +function tick() + -- Background + clear_screen(0xFF131313) + + -- Color ARGB, x, y + draw_pixel(0xFFFF0000, 30, 30) + + -- Color ARGB, thickness, x1, y1, x2, y2, xn, yn, ... + draw_line(0xFFFF00FF, 8, 100, 100, 200, 400, 300, 600) --> { Vec2, ... } + -- Color ARGB, thickness, x1, y1, x2, y2, xn, yn, ... + draw_poly(0xFFFF00FF, 8, 100, 100, 200, 400, 300, 600) --> Rect + + -- Color ARGB, radius, x, y, start, end + draw_circle(0xFFFF0000, 20, 300, 300) --> Rect + -- Color ARGB, outer, inner, x, y, start, end + draw_ring(0xFF00FF00, 30, 20, 300, 300) --> Rect + + -- Color ARGB, x, y, w, h + draw_rect_fill(0xFF00FFFF, 100, 700, 320, 240) --> Rect + -- Color ARGB, thickness, x, y, w, h + draw_rect(0xFFFF00FF, 8, 100, 700, 320, 240) --> Rect + + -- font, text, size, x, y, Color ARGB + draw_text(font, "Hello, world!", 32, 400, 400, 0xFFFF00FF) --> Rect + + -- image ptr x, y, w, h, src_x, src_y, src_w, src_h + draw_image( img, 0, 0) --> Rect +end + +function unload() + image_free(img) + font_free(font) +end diff --git a/src/main.c b/src/main.c index cbcecc0..b32efe8 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,45 @@ +#include +#include #include #include +#include +#include + +#include "sdl_xroot.h" + +struct sdlxroot_context ctx; +SDL_Renderer *renderer; + +volatile bool running = true; + +void cleanup(void) { + SDL_DestroyRenderer(renderer); + sdlxroot_close(&ctx); +} + +void sighandler(int sig) { + running = false; +} int main(void) { - printf("Hi!\n"); + if (!sdlxroot_create(NULL, &ctx)) { + fprintf(stderr, "Failed creating window or something\n"); + return EXIT_FAILURE; + } + + 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); + usleep(1000); + } + + return EXIT_SUCCESS; } diff --git a/src/rootwindow.c b/src/rootwindow.c new file mode 100644 index 0000000..0940299 --- /dev/null +++ b/src/rootwindow.c @@ -0,0 +1,119 @@ +#include "rootwindow.h" +#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); + +Window create_root_window(Display *display, int screen) { + // below, sticky, fullscreen, skip_taskbar, skip_pager, noFocus, override, + // set_desktop_type + + XSetWindowAttributes attrs = { + ParentRelative, 0L, 0, 0L, 0, 0, Always, 0L, 0L, False, StructureNotifyMask | ExposureMask, 0L, True, 0, 0 + }; + + int screen_w = DisplayWidth(display, screen), + screen_h = DisplayHeight(display, screen); + + Window root, desktop; + if (!find_desktop_window(display, screen, &root, &desktop)) { + fprintf(stderr, "find_desktop_window() failed\n"); + return 0; + } + + 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)); + } + XLowerWindow(display, window); + XMapWindow(display, window); + XSync(display, window); + return window; +} + +// 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 */ + + for (i = 0; i < 10; i++) { + XQueryTree(display, win, &troot, &parent, &children, &n); + + for (j = 0; j < n; j++) { + XWindowAttributes attrs; + + 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; + } + } + } + + XFree(children); + if (j == n) { + break; + } + } + + 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 new file mode 100644 index 0000000..f24000e --- /dev/null +++ b/src/rootwindow.h @@ -0,0 +1,8 @@ +#ifndef _ROOTWINDOW_H_ +#define _ROOTWINDOW_H_ + +#include + +Window create_root_window(Display *display, int screen); + +#endif diff --git a/src/sdl_xroot.c b/src/sdl_xroot.c new file mode 100644 index 0000000..f3301ea --- /dev/null +++ b/src/sdl_xroot.c @@ -0,0 +1,40 @@ + +#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 new file mode 100644 index 0000000..6a032e4 --- /dev/null +++ b/src/sdl_xroot.h @@ -0,0 +1,17 @@ +#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