diff --git a/clients/.gitignore b/clients/.gitignore index c369f6a9..b0363bfe 100644 --- a/clients/.gitignore +++ b/clients/.gitignore @@ -17,3 +17,4 @@ desktop-shell-client-protocol.h desktop-shell-protocol.c desktop-shell simple-client +wscreensaver diff --git a/clients/Makefile.am b/clients/Makefile.am index bae9f3f0..1f7125ff 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -23,6 +23,7 @@ clients_programs = \ dnd \ smoke \ resizor \ + wscreensaver \ eventdemo desktop_shell = wayland-desktop-shell @@ -69,6 +70,9 @@ smoke_LDADD = $(toolkit_libs) resizor_SOURCES = resizor.c resizor_LDADD = $(toolkit_libs) +wscreensaver_SOURCES = wscreensaver.c wscreensaver-glue.c glmatrix.c +wscreensaver_LDADD = $(toolkit_libs) -lGLU + eventdemo_SOURCES = eventdemo.c eventdemo_LDADD = $(toolkit_libs) diff --git a/clients/glmatrix.c b/clients/glmatrix.c index a5003185..4da04f34 100644 --- a/clients/glmatrix.c +++ b/clients/glmatrix.c @@ -28,17 +28,14 @@ #undef BELLRAND #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) -#include "xlockmore.h" -#include "xpm-ximage.h" +#include "wscreensaver-glue.h" #ifdef __GNUC__ __extension__ /* don't warn about "string length is greater than the length ISO C89 compilers are required to support" when including the following XPM file... */ #endif -#include "../images/matrix3.xpm" - -#ifdef USE_GL /* whole file */ +#include "matrix3.xpm" #define DEF_SPEED "1.0" @@ -188,6 +185,7 @@ static Bool do_rotate; static Bool do_texture; static char *mode_str; +#if 0 static XrmOptionDescRec opts[] = { { "-speed", ".speed", XrmoptionSepArg, 0 }, { "-density", ".density", XrmoptionSepArg, 0 }, @@ -222,7 +220,7 @@ static argtype vars[] = { }; ENTRYPOINT ModeSpecOpt matrix_opts = {countof(opts), opts, countof(vars), vars, NULL}; - +#endif /* Re-randomize the state of one strip. */ @@ -589,6 +587,7 @@ reshape_matrix (ModeInfo *mi, int width, int height) } +#if 0 ENTRYPOINT Bool matrix_handle_event (ModeInfo *mi, XEvent *event) { @@ -609,7 +608,7 @@ matrix_handle_event (ModeInfo *mi, XEvent *event) return False; } - +#endif #if 0 static Bool @@ -695,8 +694,7 @@ load_textures (ModeInfo *mi, Bool flip_p) /* The Matrix XPM is 512x598 -- but GL texture sizes must be powers of 2. So we waste some padding rows to round up. */ - xi = xpm_to_ximage (mi->dpy, mi->xgwa.visual, mi->xgwa.colormap, - matrix3_xpm); + xi = xpm_to_ximage (matrix3_xpm); orig_w = xi->width; orig_h = xi->height; mp->real_char_rows = CHAR_ROWS; @@ -990,8 +988,6 @@ ENTRYPOINT void draw_matrix (ModeInfo *mi) { matrix_configuration *mp = &mps[MI_SCREEN(mi)]; - Display *dpy = MI_DISPLAY(mi); - Window window = MI_WINDOW(mi); int i; if (!mp->glx_context) @@ -1057,9 +1053,12 @@ draw_matrix (ModeInfo *mi) if (mi->fps_p) do_fps (mi); glFinish(); - glXSwapBuffers(dpy, window); + glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi)); } -XSCREENSAVER_MODULE_2 ("GLMatrix", glmatrix, matrix) - -#endif /* USE_GL */ +WL_EXPORT struct wscreensaver_plugin glmatrix_screensaver = { + "GLMatrix", + init_matrix, + draw_matrix, + reshape_matrix +}; diff --git a/clients/wscreensaver-glue.c b/clients/wscreensaver-glue.c new file mode 100644 index 00000000..a5485994 --- /dev/null +++ b/clients/wscreensaver-glue.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2011 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "wscreensaver-glue.h" + +double frand(double f) +{ + double r = random(); + return r * f / (double)RAND_MAX; +} + +void clear_gl_error(void) +{ + while (glGetError() != GL_NO_ERROR) + ; +} + +void check_gl_error(const char *msg) +{ + const char *emsg; + int err = glGetError(); + + switch (err) + { + case GL_NO_ERROR: + return; + + #define ERR(tok) case tok: emsg = #tok; break; + ERR(GL_INVALID_ENUM) + ERR(GL_INVALID_VALUE) + ERR(GL_INVALID_OPERATION) + ERR(GL_STACK_OVERFLOW) + ERR(GL_STACK_UNDERFLOW) + ERR(GL_OUT_OF_MEMORY) + #undef ERR + + default: + fprintf(stderr, "%s: %s: unknown GL error 0x%04x\n", + progname, msg, err); + exit(1); + } + + fprintf(stderr, "%s: %s: GL error %s\n", progname, msg, emsg); + exit(1); +} + +static void +read_xpm_color(uint32_t *ctable, const char *line) +{ + unsigned char key; + char cstr[10]; + char *end; + uint32_t value; + + if (sscanf(line, "%1c c %9s", &key, cstr) < 2) { + fprintf(stderr, "%s: error in XPM color definition '%s'\n", + progname, line); + return; + } + + value = strtol(&cstr[1], &end, 16); + + if (strcmp(cstr, "None") == 0) + ctable[key] = 0x00ffffff; + else if (cstr[0] != '#' || !(cstr[1] != '\0' && *end == '\0')) { + fprintf(stderr, "%s: error interpreting XPM color '%s'\n", + progname, cstr); + return; + } + + ctable[key] = value | 0xff000000; +} + +static void +read_xpm_row(char *data, const char *line, uint32_t *ctable, int width) +{ + uint32_t *pixel = (uint32_t *)data; + uint8_t *p = (uint8_t *)line; + int i; + + for (i = 0; i < width; ++i) + pixel[i] = ctable[p[i]]; +} + +XImage *xpm_to_ximage(char **xpm_data) +{ + XImage *xi; + int colors; + int cpp; + int i; + uint32_t ctable[256] = { 0 }; + + xi = malloc(sizeof *xi); + if (!xi) + return NULL; + xi->data = NULL; + + if (sscanf(xpm_data[0], "%d %d %d %d", &xi->width, + &xi->height, &colors, &cpp) < 4) + goto errout; + + if (xi->width < 1 || xi->height < 1 || cpp != 1) + goto errout; + + xi->bytes_per_line = xi->width * sizeof(uint32_t); + xi->data = malloc(xi->height * xi->bytes_per_line); + if (!xi->data) + goto errout; + + for (i = 0; i < colors; ++i) + read_xpm_color(ctable, xpm_data[i + 1]); + + for (i = 0; i < xi->height; ++i) + read_xpm_row(xi->data + i * xi->bytes_per_line, + xpm_data[i + colors + 1], ctable, xi->width); + + return xi; + +errout: + fprintf(stderr, "%s: error processing XPM data.\n", progname); + XDestroyImage(xi); + return NULL; +} + +void XDestroyImage(XImage *xi) +{ + free(xi->data); + free(xi); +} diff --git a/clients/wscreensaver-glue.h b/clients/wscreensaver-glue.h new file mode 100644 index 00000000..74c9e5c6 --- /dev/null +++ b/clients/wscreensaver-glue.h @@ -0,0 +1,121 @@ +/* + * Copyright © 2011 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifndef WSCREENSAVER_GLUE_H +#define WSCREENSAVER_GLUE_H + +/* + * This file is glue, that tries to avoid changing glmatrix.c from the + * original too much, hopefully easing the porting of other (GL) + * xscreensaver "hacks". + */ + +#include "wscreensaver.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "wayland-util.h" +#include "window.h" + +#define ENTRYPOINT static + +typedef bool Bool; +#define True true +#define False false + +typedef struct ModeInfo ModeInfo; + +#define MI_DISPLAY(mi) NULL +#define MI_WINDOW(mi) (mi) +#define MI_SCREEN(mi) ((mi)->instance_number) +#define MI_WIDTH(mi) ((mi)->width) +#define MI_HEIGHT(mi) ((mi)->height) +#define MI_IS_WIREFRAME(mi) 0 +#define MI_NUM_SCREENS(mi) 16 + +typedef EGLContext GLXContext; + +double frand(double f); +void clear_gl_error(void); +void check_gl_error(const char *msg); + +static inline void +glXMakeCurrent(void *dummy, ModeInfo *mi, EGLContext ctx) +{ + assert(mi->eglctx == ctx); +} + +static inline void +glXSwapBuffers(void *dummy, ModeInfo *mi) +{ + mi->swap_buffers = 1; +} + +static inline void +do_fps(ModeInfo *mi) +{ +} + +/* just enough XImage to satisfy glmatrix.c */ + +typedef struct _XImage { + int width; + int height; + char *data; + int bytes_per_line; +} XImage; + +XImage *xpm_to_ximage(char **xpm_data); +void XDestroyImage(XImage *xi); + +static inline unsigned long +XGetPixel(XImage *xi, int x, int y) +{ + return *(uint32_t *)(xi->data + xi->bytes_per_line * y + 4 * x); +} + +static inline void +XPutPixel(XImage *xi, int x, int y, unsigned long pixel) +{ + *(uint32_t *)(xi->data + xi->bytes_per_line * y + 4 * x) = pixel; +} + +/* + * override glViewport from the plugin, so we can set it up properly + * rendering to a regular decorated Wayland window. + */ +#ifdef glViewport +#undef glViewport +#endif +#define glViewport(x,y,w,h) do {} while (0) + +#endif /* WSCREENSAVER_GLUE_H */ diff --git a/clients/wscreensaver.c b/clients/wscreensaver.c new file mode 100644 index 00000000..6070c5df --- /dev/null +++ b/clients/wscreensaver.c @@ -0,0 +1,275 @@ +/* + * Copyright © 2011 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "config.h" + +#include "wscreensaver.h" + +#include +#include +#include +#include + +#include +#include + +#include "wayland-util.h" +#include "wayland-client.h" + +#include "window.h" + +extern struct wscreensaver_plugin glmatrix_screensaver; + +static const struct wscreensaver_plugin * const plugins[] = { + &glmatrix_screensaver, + NULL +}; + +const char *progname = NULL; + +struct wscreensaver { + struct display *display; + + /* per output, if fullscreen mode */ + struct ModeInfo *modeinfo; + + struct { + EGLDisplay display; + EGLConfig config; + } egl; + + const struct wscreensaver_plugin *plugin; +}; + +static void +draw_instance(struct ModeInfo *mi) +{ + struct wscreensaver *wscr = mi->priv; + struct rectangle drawarea; + struct rectangle winarea; + int bottom; + + mi->swap_buffers = 0; + + window_draw(mi->window); + + window_get_child_allocation(mi->window, &drawarea); + window_get_allocation(mi->window, &winarea); + + if (display_acquire_window_surface(wscr->display, + mi->window, + mi->eglctx) < 0) { + fprintf(stderr, "%s: unable to acquire window surface", + progname); + return; + } + + bottom = winarea.height - (drawarea.height + drawarea.y); + glViewport(drawarea.x, bottom, drawarea.width, drawarea.height); + glScissor(drawarea.x, bottom, drawarea.width, drawarea.height); + glEnable(GL_SCISSOR_TEST); + + if (mi->width != drawarea.width || mi->height != drawarea.height) { + mi->width = drawarea.width; + mi->height = drawarea.height; + wscr->plugin->reshape(mi, mi->width, mi->height); + } + + wscr->plugin->draw(mi); + + if (mi->swap_buffers == 0) + fprintf(stderr, "%s: swapBuffers not called\n", progname); + + display_release_window_surface(wscr->display, mi->window); + window_flush(mi->window); +} + +static void +frame_callback(void *data, struct wl_callback *callback, uint32_t time) +{ + struct ModeInfo *mi = data; + static const struct wl_callback_listener listener = { + frame_callback + }; + + draw_instance(mi); + + if (callback) + wl_callback_destroy(callback); + + callback = wl_surface_frame(window_get_wl_surface(mi->window)); + wl_callback_add_listener(callback, &listener, mi); +} + +static void +init_frand(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + srandom(tv.tv_sec * 100 + tv.tv_usec / 10000); +} + +WL_EXPORT EGLContext * +init_GL(struct ModeInfo *mi) +{ + struct wscreensaver *wscr = mi->priv; + EGLContext *pctx; + + pctx = malloc(sizeof *pctx); + if (!pctx) + return NULL; + + if (mi->eglctx != EGL_NO_CONTEXT) { + fprintf(stderr, "%s: multiple GL contexts are not supported", + progname); + goto errout; + } + + mi->eglctx = eglCreateContext(wscr->egl.display, wscr->egl.config, + EGL_NO_CONTEXT, NULL); + if (mi->eglctx == EGL_NO_CONTEXT) { + fprintf(stderr, "%s: init_GL failed to create EGL context\n", + progname); + goto errout; + } + + if (!eglMakeCurrent(wscr->egl.display, NULL, NULL, mi->eglctx)) { + fprintf(stderr, "%s: init_GL failed on eglMakeCurrent\n", + progname); + goto errout; + } + + glClearColor(0.0, 0.0, 0.0, 1.0); + + *pctx = mi->eglctx; + return pctx; + +errout: + free(pctx); + return NULL; +} + +static struct ModeInfo * +create_modeinfo(struct wscreensaver *wscr, struct window *window) +{ + struct ModeInfo *mi; + struct rectangle drawarea; + + mi = calloc(1, sizeof *mi); + if (!mi) + return NULL; + + window_get_child_allocation(window, &drawarea); + + mi->priv = wscr; + mi->eglctx = EGL_NO_CONTEXT; + + mi->window = window; + + mi->instance_number = 0; /* XXX */ + mi->width = drawarea.width; + mi->height = drawarea.height; + + return mi; +} + +static struct ModeInfo * +create_wscreensaver_instance(struct wscreensaver *wscr) +{ + struct ModeInfo *mi; + struct window *window; + + window = window_create(wscr->display, 400, 300); + if (!window) { + fprintf(stderr, "%s: creating a window failed.\n", progname); + return NULL; + } + + window_set_transparent(window, 0); + window_set_title(window, progname); + + mi = create_modeinfo(wscr, window); + if (!mi) + return NULL; + + wscr->plugin->init(mi); + + frame_callback(mi, NULL, 0); + return mi; +} + +/* returns error message, or NULL if success */ +static const char * +init_wscreensaver(struct wscreensaver *wscr, struct display *display) +{ + int size; + const char prefix[] = "wscreensaver::"; + char *str; + + wscr->display = display; + wscr->plugin = plugins[0]; + + size = sizeof(prefix) + strlen(wscr->plugin->name); + str = malloc(size); + if (!str) + return "out of memory"; + snprintf(str, size, "%s%s", prefix, wscr->plugin->name); + progname = str; + + wscr->egl.display = display_get_egl_display(wscr->display); + if (!wscr->egl.display) + return "no EGL display"; + + eglBindAPI(EGL_OPENGL_API); + wscr->egl.config = display_get_rgb_egl_config(wscr->display); + + wscr->modeinfo = create_wscreensaver_instance(wscr); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + struct display *d; + struct wscreensaver wscr = { 0 }; + const char *msg; + + init_frand(); + + d = display_create(&argc, &argv, NULL); + if (d == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + return EXIT_FAILURE; + } + + msg = init_wscreensaver(&wscr, d); + if (msg) { + fprintf(stderr, "wscreensaver init failed: %s\n", msg); + return EXIT_FAILURE; + } + + display_run(d); + + free((void *)progname); + + return EXIT_SUCCESS; +} diff --git a/clients/wscreensaver.h b/clients/wscreensaver.h new file mode 100644 index 00000000..016dd199 --- /dev/null +++ b/clients/wscreensaver.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2011 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifndef WSCREENSAVER_H +#define WSCREENSAVER_H + +#define MESA_EGL_NO_X11_HEADERS +#include + +extern const char *progname; + +struct wscreensaver; + +struct ModeInfo { + struct wscreensaver *priv; + EGLContext eglctx; + int swap_buffers; + + struct window *window; + + int instance_number; + unsigned width; + unsigned height; + + unsigned long polygon_count; + int fps_p; +}; + +struct wscreensaver_plugin { + const char *name; + void (*init)(struct ModeInfo *mi); + void (*draw)(struct ModeInfo *mi); + void (*reshape)(struct ModeInfo *mi, int w, int h); +/* void (*refresh)(struct ModeInfo *mi); + void (*finish)(struct ModeInfo *mi);*/ +}; + +EGLContext * +init_GL(struct ModeInfo *mi); + +#endif /* WSCREENSAVER_H */