summaryrefslogtreecommitdiff
path: root/clients/wscreensaver.c
diff options
context:
space:
mode:
Diffstat (limited to 'clients/wscreensaver.c')
-rw-r--r--clients/wscreensaver.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/clients/wscreensaver.c b/clients/wscreensaver.c
new file mode 100644
index 00000000..9a2c47ad
--- /dev/null
+++ b/clients/wscreensaver.c
@@ -0,0 +1,344 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <GL/gl.h>
+#include <EGL/eglext.h>
+
+#include <wayland-client.h>
+
+#include "desktop-shell-client-protocol.h"
+#include "window.h"
+
+extern struct wscreensaver_plugin glmatrix_screensaver;
+
+static const struct wscreensaver_plugin * const plugins[] = {
+ &glmatrix_screensaver,
+ NULL
+};
+
+const char *progname = NULL;
+
+static int demo_mode;
+
+struct wscreensaver {
+ struct screensaver *interface;
+
+ struct display *display;
+
+ struct ModeInfo *demomode;
+
+ struct {
+ EGLDisplay display;
+ EGLConfig config;
+ } egl;
+
+ const struct wscreensaver_plugin *plugin;
+};
+
+static void
+frame_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct ModeInfo *mi = data;
+
+ window_schedule_redraw(mi->window);
+ wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener listener = {
+ frame_callback
+};
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+ struct ModeInfo *mi = data;
+ struct wscreensaver *wscr = mi->priv;
+ struct rectangle drawarea;
+ struct rectangle winarea;
+ struct wl_callback *callback;
+ int bottom;
+
+ mi->swap_buffers = 0;
+
+ widget_get_allocation(mi->widget, &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);
+
+ 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_wscreensaver_instance(struct wscreensaver *screensaver,
+ struct wl_output *output, int width, int height)
+{
+ static int instance;
+ struct ModeInfo *mi;
+ struct rectangle drawarea;
+
+ mi = calloc(1, sizeof *mi);
+ if (!mi)
+ return NULL;
+
+ if (demo_mode)
+ mi->window = window_create(screensaver->display);
+ else
+ mi->window = window_create_custom(screensaver->display);
+
+ if (!mi->window) {
+ fprintf(stderr, "%s: creating a window failed.\n", progname);
+ free(mi);
+ return NULL;
+ }
+
+ window_set_title(mi->window, progname);
+
+ if (screensaver->interface && !demo_mode) {
+ mi->widget = window_add_widget(mi->window, mi);
+ screensaver_set_surface(screensaver->interface,
+ window_get_wl_surface(mi->window),
+ output);
+ } else {
+ mi->widget = frame_create(mi->window, mi);
+ }
+ widget_set_redraw_handler(mi->widget, redraw_handler);
+
+ mi->priv = screensaver;
+ mi->eglctx = EGL_NO_CONTEXT;
+ mi->instance_number = instance++; /* XXX */
+
+ widget_get_allocation(mi->widget, &drawarea);
+ mi->width = drawarea.width;
+ mi->height = drawarea.height;
+
+ screensaver->plugin->init(mi);
+
+ window_schedule_resize(mi->window, width, height);
+ return mi;
+}
+
+static void
+handle_output_destroy(struct output *output, void *data)
+{
+ /* struct ModeInfo *mi = data;
+ * TODO */
+}
+
+static void
+handle_output_configure(struct output *output, void *data)
+{
+ struct wscreensaver *screensaver = data;
+ struct ModeInfo *mi;
+ struct rectangle area;
+
+ /* skip existing outputs */
+ if (output_get_user_data(output))
+ return;
+
+ output_get_allocation(output, &area);
+ mi = create_wscreensaver_instance(screensaver,
+ output_get_wl_output(output),
+ area.width, area.height);
+ output_set_user_data(output, mi);
+ output_set_destroy_handler(output, handle_output_destroy);
+}
+
+static int
+init_wscreensaver(struct wscreensaver *wscr, struct display *display)
+{
+ int size;
+ const char prefix[] = "wscreensaver::";
+ char *str;
+
+ display_set_user_data(display, wscr);
+ wscr->display = display;
+ wscr->plugin = plugins[0];
+
+ size = sizeof(prefix) + strlen(wscr->plugin->name);
+ str = malloc(size);
+ if (!str) {
+ fprintf(stderr, "init: out of memory\n");
+ return -1;
+ }
+ snprintf(str, size, "%s%s", prefix, wscr->plugin->name);
+ progname = str;
+
+ wscr->egl.display = display_get_egl_display(wscr->display);
+ if (!wscr->egl.display) {
+ fprintf(stderr, "init: no EGL display\n");
+ return -1;
+ }
+
+ eglBindAPI(EGL_OPENGL_API);
+ wscr->egl.config = display_get_argb_egl_config(wscr->display);
+
+ if (demo_mode) {
+ struct wl_output *o =
+ output_get_wl_output(display_get_output(display));
+ /* only one instance */
+ wscr->demomode =
+ create_wscreensaver_instance(wscr, o, 400, 300);
+ return 0;
+ }
+
+ display_set_output_configure_handler(display, handle_output_configure);
+
+ return 0;
+}
+
+static void
+global_handler(struct display *display, uint32_t name,
+ const char *interface, uint32_t version, void *data)
+{
+ struct wscreensaver *screensaver = data;
+
+ if (!strcmp(interface, "screensaver")) {
+ screensaver->interface =
+ display_bind(display, name, &screensaver_interface, 1);
+ }
+}
+
+static const struct weston_option wscreensaver_options[] = {
+ { WESTON_OPTION_BOOLEAN, "demo", 0, &demo_mode },
+};
+
+int main(int argc, char *argv[])
+{
+ struct display *d;
+ struct wscreensaver screensaver = { 0 };
+
+ init_frand();
+
+ parse_options(wscreensaver_options,
+ ARRAY_LENGTH(wscreensaver_options), &argc, argv);
+
+ d = display_create(&argc, argv);
+ if (d == NULL) {
+ fprintf(stderr, "failed to create display: %m\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!demo_mode) {
+ /* iterates already known globals immediately */
+ display_set_user_data(d, &screensaver);
+ display_set_global_handler(d, global_handler);
+ if (!screensaver.interface) {
+ fprintf(stderr,
+ "Server did not offer screensaver interface,"
+ " exiting.\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (init_wscreensaver(&screensaver, d) < 0) {
+ fprintf(stderr, "wscreensaver init failed.\n");
+ return EXIT_FAILURE;
+ }
+
+ display_run(d);
+
+ free((void *)progname);
+
+ return EXIT_SUCCESS;
+}