/*
* Copyright © 2011 Alberto Ruiz <alberto.ruiz@codethink.co.uk>
* Copyright © 2011 Codethink 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 <wayland-client.h>
#include <wayland-egl.h>
#include <cairo.h>
#include <cairo-gl.h>
#include <EGL/egl.h>
#include <stdio.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
struct client_info {
uint32_t mask;
struct wl_compositor *comp;
struct wl_egl_display *native;
struct wl_egl_window *window;
struct wl_display *disp;
EGLDisplay egl_display;
EGLSurface egl_surface;
EGLConfig conf;
EGLContext context;
struct wl_surface *surface;
cairo_device_t *cr_device;
cairo_surface_t *cr_surface;
int run;
};
void
wl_egl_init (struct client_info *info)
{
EGLint major, minor;
EGLint n;
static const EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_DEPTH_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
};
info->egl_display = eglGetDisplay(info->native);
eglInitialize(info->egl_display, &major, &minor);
eglBindAPI(EGL_OPENGL_API);
eglChooseConfig(info->egl_display, config_attribs, &info->conf, 1, &n);
info->context = eglCreateContext(info->egl_display,
info->conf,
EGL_NO_CONTEXT,
NULL);
eglMakeCurrent(info->egl_display, NULL, NULL, info->context);
info->cr_device = cairo_egl_device_create(info->egl_display, info->context);
return;
}
static int
event_mask_update (uint32_t mask, void *data)
{
((struct client_info*)data)->mask = mask;
return 0;
}
/* This callback is called by wl_display_frame_callback and performs cairo operations
* over the window surface to then swap buffers and show the results in the client window
*/
static void
redraw(struct wl_surface *surface, void *data, uint32_t time)
{
struct client_info *info = (struct client_info*)data;
cairo_t *cr;
cr = cairo_create (info->cr_surface);
cairo_set_line_width (cr, 1.0);
cairo_rectangle (cr, 0.25, 0.25, 70.0, 70.0);
cairo_set_source_rgb (cr, (time % 9 + 1) * 0.1, (time % 5 + 1) * 0.1, (time % 3 + 1) * 0.3);
cairo_fill (cr);
cairo_destroy (cr);
cairo_gl_surface_swapbuffers(info->cr_surface);
/* We need to call wl_display_frame_callback again if we want to redraw the surface past this point */
}
static void
display_handle_global (struct wl_display *disp,
uint32_t id,
const char *iface,
uint32_t version,
void *data)
{
struct client_info* info = (struct client_info*)data;
fprintf (stderr, "- WAYLAND DISPLAY INTERFACE: %s\n", iface);
if (!strcmp(iface, "compositor"))
info->comp = wl_compositor_create (disp, id);
}
/* This callback is called when the connection with the display server
* is finished and gets hold of the compositor object to create a window
* surface.
*/
static void
sync_handle (void *data)
{
struct wl_visual *visual;
struct client_info *info = (struct client_info*)data;
if (!info->comp) {
fprintf (stderr, "No compositor object was found\n");
info->run = FALSE;
return;
}
/* The compositor is now available, we crate a window surface */
info->surface = wl_compositor_create_surface(info->comp);
visual = wl_display_get_premultiplied_argb_visual(info->disp);
info->window = wl_egl_window_create(info->egl_display,
info->surface,
100,
100,
visual);
info->egl_surface = eglCreateWindowSurface(info->egl_display,
info->conf,
info->window,
NULL);
eglMakeCurrent(info->egl_display, info->egl_surface,
info->egl_surface, info->context);
info->cr_surface = cairo_gl_surface_create_for_egl(info->cr_device,
info->egl_surface,
100, 100);
wl_surface_map_toplevel(info->surface);
wl_display_frame_callback(info->disp, info->surface, redraw, info);
}
int
main (int argc, char** argv)
{
struct client_info info = {0};
struct wl_display *disp = wl_display_connect (NULL);
info.run = TRUE;
info.disp = disp;
wl_display_add_global_listener(disp, display_handle_global, &info);
info.native = wl_egl_display_create(disp);
wl_egl_init (&info);
wl_display_get_fd (disp, event_mask_update, &info);
wl_display_sync_callback(disp, sync_handle, &info);
while (info.run)
wl_display_iterate (disp, info.mask);
return 0;
}