| /* |
| * 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; |
| } |