#include #include #include #include #include #include #include #include #include #include struct display { struct wl_display *display; struct { struct wl_compositor *compositor; struct wl_shell *shell; } interface; struct { EGLDisplay dpy; EGLConfig conf; EGLContext ctx; } egl; cairo_device_t *cairo_device; uint32_t mask; }; struct window { struct display *display; struct wl_surface *surface; struct wl_egl_window *egl_window; int width, height; struct { EGLSurface surf; } egl; cairo_surface_t *cairo_surface; }; static void init_egl(struct display *display) { EGLint major, minor; EGLint num_config; EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, EGL_DEPTH_SIZE, 1, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE }; display->egl.dpy = eglGetDisplay(display->display); assert(display->egl.dpy); assert(eglInitialize(display->egl.dpy, &major, &minor)); assert(eglBindAPI(EGL_OPENGL_API)); assert(eglChooseConfig(display->egl.dpy, config_attribs, &display->egl.conf, 1, &num_config)); assert(num_config == 1); display->egl.ctx = eglCreateContext(display->egl.dpy, display->egl.conf, EGL_NO_CONTEXT, NULL); assert(display->egl.ctx); display->cairo_device = cairo_egl_device_create(display->egl.dpy, display->egl.ctx); assert(display->cairo_device); } static const cairo_user_data_key_t surface_data_key; static void egl_window_surface_data_destroy(void *p) { struct window *window = p; struct display *d = window->display; eglDestroySurface(d->egl.dpy, window->egl.surf); wl_egl_window_destroy(window->egl_window); } static void create_cairo_window_surface(struct display *display, struct window *window) { struct wl_visual *visual; window->egl_window = wl_egl_window_create(window->surface, window->width, window->height); window->egl.surf = eglCreateWindowSurface(display->egl.dpy, display->egl.conf, window->egl_window, NULL); window->cairo_surface = cairo_gl_surface_create_for_egl(display->cairo_device, window->egl.surf, window->width, window->height); cairo_surface_set_user_data(window->cairo_surface, &surface_data_key, window, egl_window_surface_data_destroy); } static const struct wl_callback_listener frame_listener; static void redraw(void *data, struct wl_callback *callback, uint32_t time) { struct window *window = data; cairo_t *cr; cairo_pattern_t *pattern; int x,y; int width = window->width; int height = window->height; cr = cairo_create(window->cairo_surface); int speed_div = 100; double pos = time % (speed_div * 360) * 1.0 / speed_div; #if 0 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 1, 1, 1, 1); cairo_paint(cr); /* Quadrate im Hintergrund zeichnen */ for (x=0; x<10; x++) for (y=0; y<10; y++) cairo_rectangle(cr, x*10.0, y*10.0, 5, 5); pattern = cairo_pattern_create_radial(50, 50, 5, 50, 50, 50); cairo_pattern_add_color_stop_rgb(pattern, 0, 0.75, 0.15, 0.99); cairo_pattern_add_color_stop_rgb(pattern, 0.9, 1, 1, 1); cairo_set_source(cr, pattern); #else cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, 0, 0, 0); cairo_paint(cr); cairo_set_line_width(cr, 9); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_arc(cr, width/2, height/2, (width < height ? width : height) / 2 - 10, pos, pos+M_PI); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.3, 0.4, 0.6); #endif cairo_fill(cr); cairo_destroy(cr); if (callback) wl_callback_destroy(callback); callback = wl_surface_frame(window->surface); wl_callback_add_listener(callback, &frame_listener, window); cairo_gl_surface_swapbuffers(window->cairo_surface); } static const struct wl_callback_listener frame_listener = { redraw }; enum window_location { WINDOW_INTERIOR = 0, WINDOW_RESIZING_TOP = 1, WINDOW_RESIZING_BOTTOM = 2, WINDOW_RESIZING_LEFT = 4, WINDOW_RESIZING_TOP_LEFT = 5, WINDOW_RESIZING_BOTTOM_LEFT = 6, WINDOW_RESIZING_RIGHT = 8, WINDOW_RESIZING_TOP_RIGHT = 9, WINDOW_RESIZING_BOTTOM_RIGHT = 10, WINDOW_RESIZING_MASK = 15, WINDOW_EXTERIOR = 16, WINDOW_TITLEBAR = 17, WINDOW_CLIENT_AREA = 18, }; static void handle_configure(void *data, struct wl_shell *shell, uint32_t time, uint32_t edges, struct wl_surface *surface, int32_t width, int32_t height) { struct window *window = wl_surface_get_user_data(surface); int dx = 0; int dy = 0; int a_width, a_height; wl_egl_window_get_attached_size(window->egl_window, &a_width, &a_height); if (edges & WINDOW_RESIZING_LEFT) dx = a_width - width; if (edges & WINDOW_RESIZING_TOP) dy = a_height - height; wl_egl_window_resize(window->egl_window, width, height, dx, dy); cairo_gl_surface_set_size(window->cairo_surface, width, height); window->width = width; window->height = height; } static const struct wl_shell_listener wayland_shell_listener = { handle_configure, }; static void display_handle_global(struct wl_display *display, uint32_t id, const char *interface, uint32_t version, void *data) { struct display *d = data; if (strcmp(interface, "wl_compositor") == 0) { d->interface.compositor = wl_display_bind(display, id, &wl_compositor_interface); } else if (strcmp(interface, "wl_shell") == 0) { d->interface.shell = wl_display_bind(display, id, &wl_shell_interface); wl_shell_add_listener(d->interface.shell, &wayland_shell_listener, d); } } static int event_mask_update(uint32_t mask, void *data) { struct display *d = data; d->mask = mask; return 0; } int main(int argc, char **argv) { struct display display = { 0 }; struct window window = { 0 }; window.display = &display; window.width = 100; window.height = 100; display.display = wl_display_connect(NULL); assert(display.display); wl_display_add_global_listener(display.display, display_handle_global, &display); /* process connection events */ wl_display_iterate(display.display, WL_DISPLAY_READABLE); init_egl(&display); window.surface = wl_compositor_create_surface(display.interface.compositor); wl_surface_set_user_data(window.surface, &window); create_cairo_window_surface(&display, &window); wl_shell_set_toplevel(display.interface.shell, window.surface); wl_display_get_fd(display.display, event_mask_update, &display); redraw(&window, NULL, 0); while (true) wl_display_iterate(display.display, display.mask); return 0; }