From 16b8c35b3b3df5d47bbec1ffc79ddfa711a74ed1 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 7 Sep 2019 19:23:47 +0300 Subject: [PATCH] trying to make this into a standalone xscreensaver module --- Makefile | 4 +- src/main_x11.c | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vroot.h | 142 +++++++++++++++++++++++++ 3 files changed, 467 insertions(+), 2 deletions(-) create mode 100644 src/main_x11.c create mode 100644 src/vroot.h diff --git a/Makefile b/Makefile index 3a89b00..0fc7e97 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,8 @@ ifeq ($(sys), mingw) ldflags_sys = -lmingw32 -mconsole -lfreeglut_static -lopengl32 -lglu32 -lgdi32 -lwinmm else - src_main = src/main_glut.c - ldflags_sys = -lGL -lGLU -lglut + src_main = src/main_x11.c + ldflags_sys = -lGL -lGLU -lX11 endif $(bin): $(obj) diff --git a/src/main_x11.c b/src/main_x11.c new file mode 100644 index 0000000..fe87caa --- /dev/null +++ b/src/main_x11.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "app.h" +#include "vroot.h" + +#define DEF_WIN_WIDTH 1280 +#define DEF_WIN_HEIGHT 800 + +static Window create_xwindow(void); +static int init_gl(void); +static void destroy_gl(void); +static int proc_xevent(XEvent *ev); + +static Display *dpy; +static int scr; +static Window win, root; +static GLXContext ctx; +static XVisualInfo *visinf; +static Atom xa_wm_proto, xa_wm_delwin; + +static volatile int quit; +static int mapped; + +static struct timeval tv, tv0; + +int main(int argc, char **argv) +{ + int i; + unsigned int wid; + char *endp; + + if((endp = getenv("XSCREENSAVER_WINDOW"))) { + printf("XSCREENSAVER_WINDOW: %s\n", endp); + } + + if(!(dpy = XOpenDisplay(0))) { + fprintf(stderr, "failed to open connection to the X server\n"); + return 1; + } + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False); + xa_wm_delwin = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + + for(i=0; i 0 && endp != argv[i+1]) { + printf("using window: %x\n", wid); + win = (Window)wid; + memmove(argv + i, argv + i + 2, (argc - i - 2) * sizeof *argv); + argc -= 2; + i--; + } else { + fprintf(stderr, "invalid option: -window-id must be followed by a valid window id\n"); + XCloseDisplay(dpy); + return 1; + } + } + } + + if(app_parse_args(argc, argv) == -1) { + XCloseDisplay(dpy); + return 1; + } + + if(!win && !(win = create_xwindow())) { + XCloseDisplay(dpy); + return 1; + } + if(init_gl() == -1) { + return 1; + } + if(app_init() == -1) { + destroy_gl(); + XCloseDisplay(dpy); + return 1; + } + + gettimeofday(&tv0, 0); + + while(!quit) { + while(XPending(dpy)) { + XEvent ev; + XNextEvent(dpy, &ev); + if(proc_xevent(&ev) == -1 || quit) { + goto done; + } + } + + gettimeofday(&tv, 0); + msec = (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000; + + app_display(); + + glXSwapBuffers(dpy, win); + assert(glGetError() == GL_NO_ERROR); + } + +done: + destroy_gl(); + XCloseDisplay(dpy); + return 0; +} + +void app_quit(void) +{ + exit(0); +} + +void app_fullscreen(void) +{ +} + +void app_windowed(void) +{ +} + +static XVisualInfo *choose_visual(void) +{ + int glxattr[] = { + GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 1, + GLX_SAMPLE_BUFFERS, 1, + GLX_SAMPLES, 8, + None + }; + int *sample_buffers = glxattr + 10; + int *num_samples = glxattr + 13; + XVisualInfo *res; + + do { + res = glXChooseVisual(dpy, scr, glxattr); + *num_samples >>= 1; + if(*num_samples <= 1) { + *sample_buffers = None; + } + } while(!res && *num_samples > 0); + + return res; +} + +static XVisualInfo *match_visual(Window win) +{ + int numvi, i; + XVisualInfo vitmp, *vi; + XWindowAttributes wattr; + unsigned int mask = VisualScreenMask | VisualDepthMask | VisualClassMask; + + XGetWindowAttributes(dpy, win, &wattr); + + vitmp.visualid = XVisualIDFromVisual(wattr.visual); + vi = XGetVisualInfo(dpy, VisualIDMask, &vitmp, &numvi); + vitmp = *vi; + vi = XGetVisualInfo(dpy, mask, &vitmp, &numvi); + + printf("found %d matching visuals\n", numvi); + for(i=0; ivisual, AllocNone); + xattr.background_pixel = BlackPixel(dpy, scr); + xattr_mask = CWColormap | CWBackPixel; + + if(!(win = XCreateWindow(dpy, root, 0, 0, DEF_WIN_WIDTH, DEF_WIN_HEIGHT, 0, + visinf->depth, InputOutput, visinf->visual, xattr_mask, &xattr))) { + fprintf(stderr, "failed to create X window\n"); + XFree(visinf); + visinf = 0; + return 0; + } + + evmask = ExposureMask | StructureNotifyMask | KeyPressMask; + XSelectInput(dpy, win, evmask); + + Xutf8SetWMProperties(dpy, win, "census", "census", 0, 0, 0, 0, 0); + XSetWMProtocols(dpy, win, &xa_wm_delwin, 1); + + XMapRaised(dpy, win); + return win; +} + +static int init_gl(void) +{ + XWindowAttributes wattr; + int rbits, gbits, bbits, zbits, sbits, nsamp; + + if(!win) return -1; + + XGetWindowAttributes(dpy, win, &wattr); + + if(!visinf && !(visinf = choose_visual())) { + fprintf(stderr, "failed to find appropriate visual\n"); + return -1; + } + + if(!(ctx = glXCreateContext(dpy, visinf, 0, 1))) { + fprintf(stderr, "failed to create OpenGL context\n"); + XFree(visinf); + if(win != root) { + XDestroyWindow(dpy, win); + } + return -1; + } + + glXGetConfig(dpy, visinf, GLX_RED_SIZE, &rbits); + glXGetConfig(dpy, visinf, GLX_GREEN_SIZE, &gbits); + glXGetConfig(dpy, visinf, GLX_BLUE_SIZE, &bbits); + glXGetConfig(dpy, visinf, GLX_DEPTH_SIZE, &zbits); + glXGetConfig(dpy, visinf, GLX_STENCIL_SIZE, &sbits); + glXGetConfig(dpy, visinf, GLX_SAMPLES, &nsamp); + + printf("created GLX visual %d bpp (%d%d%d), %dz, %ds, %d samp/pix\n", + visinf->depth, rbits, gbits, bbits, zbits, sbits, nsamp); + + printf("glXMakeCurrent(%p, %x, %p)\n", (void*)dpy, (unsigned int)win, (void*)ctx); + glXMakeCurrent(dpy, win, ctx); + app_reshape(wattr.width, wattr.height); + win_width = wattr.width; + win_height = wattr.height; + return 0; +} + +static void destroy_gl(void) +{ + if(visinf) { + XFree(visinf); + } + if(ctx) { + glXMakeCurrent(dpy, 0, 0); + glXDestroyContext(dpy, ctx); + } + if(win && win != root) { + XDestroyWindow(dpy, win); + } +} + +static int proc_xevent(XEvent *ev) +{ + KeySym sym; + + switch(ev->type) { + case MapNotify: + mapped = 1; + break; + + case UnmapNotify: + mapped = 0; + break; + + case ConfigureNotify: + if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) { + int w = ev->xconfigure.width; + int h = ev->xconfigure.height; + app_reshape(w, h); + win_width = w; + win_height = h; + } + break; + + case KeyPress: + case KeyRelease: + if((sym = XLookupKeysym(&ev->xkey, 0))) { + if(sym == XK_Escape) { + sym = 27; + } + app_keyboard(sym, ev->type == KeyPress); + } + break; + + case ClientMessage: + if(ev->xclient.message_type == xa_wm_proto) { + if(ev->xclient.data.l[0] == xa_wm_delwin) { + app_quit(); + } + } + break; + + default: + break; + } + + return 0; +} diff --git a/src/vroot.h b/src/vroot.h new file mode 100644 index 0000000..a6e5caa --- /dev/null +++ b/src/vroot.h @@ -0,0 +1,142 @@ +/* -*- Mode: C; tab-width: 2 -*- */ +/*****************************************************************************/ +/** Copyright 1991 by Andreas Stolcke **/ +/** Copyright 1990 by Solbourne Computer Inc. **/ +/** Longmont, Colorado **/ +/** **/ +/** All Rights Reserved **/ +/** **/ +/** Permission to use, copy, modify, and distribute this software and **/ +/** its documentation for any purpose and without fee is hereby **/ +/** granted, provided that the above copyright notice appear in all **/ +/** copies and that both that copyright notice and this permis- **/ +/** sion notice appear in supporting documentation, and that the **/ +/** name of Solbourne not be used in advertising **/ +/** in publicity pertaining to distribution of the software without **/ +/** specific, written prior permission. **/ +/** **/ +/** ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/ +/** WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF **/ +/** MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ANDREAS STOLCKE **/ +/** OR SOLBOURNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL **/ +/** DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ +/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ +/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ +/** OR PERFORMANCE OF THIS SOFTWARE. **/ +/*****************************************************************************/ +/* + * vroot.h -- Virtual Root Window handling header file + * + * This header file redefines the X11 macros RootWindow and DefaultRootWindow, + * making them look for a virtual root window as provided by certain `virtual' + * window managers like swm and tvtwm. If none is found, the ordinary root + * window is returned, thus retaining backward compatibility with standard + * window managers. + * The function implementing the virtual root lookup remembers the result of + * its last invocation to avoid overhead in the case of repeated calls + * on the same display and screen arguments. + * The lookup code itself is taken from Tom LaStrange's ssetroot program. + * + * Most simple root window changing X programs can be converted to using + * virtual roots by just including + * + * #include + * + * after all the X11 header files. It has been tested on such popular + * X clients as xphoon, xfroot, xloadimage, and xaqua. + * It also works with the core clients xprop, xwininfo, xwd, and editres + * (and is necessary to get those clients working under tvtwm). + * It does NOT work with xsetroot; get the xsetroot replacement included in + * the tvtwm distribution instead. + * + * Andreas Stolcke , 9/7/90 + * - replaced all NULL's with properly cast 0's, 5/6/91 + * - free children list (suggested by Mark Martin ), 5/16/91 + * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91 + * + * Jamie Zawinski , 28-Apr-1997 + * - use ANSI C + * + * Jamie Zawinski , 3-Sep-2003 + * - if the environment variable "XSCREENSAVER_WINDOW" is set, use that + * as the root window instead of searching for __SWM_VROOT. + * + * Jamie Zawinski , 14-Aug-2004 + * - changes to get gcc to stop whining about "type punning". + * + * Jamie Zawinski , 16-Dec-2004 + * - fixed that last fix. + */ + +#ifndef _VROOT_H_ +#define _VROOT_H_ +#define _XSCREENSAVER_VROOT_H_ + +#if !defined(lint) && !defined(SABER) +static const char vroot_rcsid[] = +"#Id: vroot.h,v 1.8 2004/12/16 05:33:54 jwz Exp #" "\n" +"#Id: vroot.h,v 1.4 1991/09/30 19:23:16 stolcke Exp stolcke #"; +#endif + +#include +#include +#include + +static Window VirtualRootWindowOfScreen(Screen *screen) +{ + static Screen *save_screen = 0; + static Window root = (Window)0; + + if(screen != save_screen) { + Display *dpy = DisplayOfScreen(screen); + Atom __SWM_VROOT = None; + int i; + Window rootReturn, parentReturn, *children; + unsigned int numChildren; + + /* first check for a hex or decimal window ID in the environment */ + const char *xss_id = getenv("XSCREENSAVER_WINDOW"); + if(xss_id && *xss_id) { + unsigned long id = 0; + char c; + if(1 == sscanf (xss_id, " 0x%lx %c", &id, &c) || + 1 == sscanf (xss_id, " %lu %c", &id, &c)) { + root = (Window) id; + save_screen = screen; + return root; + } + } + + root = RootWindowOfScreen(screen); + + /* go look for a virtual root */ + __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); + if(XQueryTree(dpy, root, &rootReturn, &parentReturn, + &children, &numChildren)) { + for(i=0; i