From: Juan Zhao <juan.j.z...@linux.intel.com> F12:default F11:scale F10:driver F9:fill F7: set toplevel to back --- clients/Makefile.am | 6 +- clients/simple-rect.c | 681 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 686 insertions(+), 1 deletions(-) create mode 100644 clients/simple-rect.c
diff --git a/clients/Makefile.am b/clients/Makefile.am index b64c38a..a790095 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -14,7 +14,8 @@ if BUILD_SIMPLE_CLIENTS simple_clients_programs = \ simple-egl \ simple-shm \ - simple-touch + simple-touch \ + simple-rect simple_egl_SOURCES = simple-egl.c simple_egl_LDADD = $(SIMPLE_CLIENT_LIBS) -lm @@ -24,6 +25,9 @@ simple_shm_LDADD = $(SIMPLE_CLIENT_LIBS) simple_touch_SOURCES = simple-touch.c simple_touch_LDADD = $(SIMPLE_CLIENT_LIBS) + +simple_rect_SOURCES = simple-rect.c +simple_rect_LDADD = $(SIMPLE_CLIENT_LIBS) -lm -lxkbcommon endif if BUILD_CLIENTS diff --git a/clients/simple-rect.c b/clients/simple-rect.c new file mode 100644 index 0000000..c3a301b --- /dev/null +++ b/clients/simple-rect.c @@ -0,0 +1,681 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <math.h> +#include <assert.h> +#include <signal.h> +#include <linux/input.h> +#include <X11/extensions/XKBcommon.h> +#include <X11/keysym.h> +#include <glib.h> + +#include <wayland-client.h> +#include <wayland-egl.h> + +#include <GLES2/gl2.h> +#include <EGL/egl.h> + +#define WINDOW_WIDTH 1280 +#define WINDOW_HEIGHT 1024 + +static void +redraw(void *data, struct wl_callback *callback, uint32_t time); + +struct display { + struct wl_display *display; + struct wl_compositor *compositor; + struct wl_output *output; + struct wl_shell *shell; + struct { + EGLDisplay dpy; + EGLContext ctx; + EGLConfig conf; + } egl; + uint32_t mask; + + struct xkb_desc *xkb; +}; + +struct window { + struct display *display; + struct { + int width, height; + } geometry; + struct { + GLuint fbo; + GLuint color_rbo; + + GLuint program; + GLuint rotation_uniform; + + GLuint pos; + GLuint col; + } gl; + + struct wl_egl_window *native; + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + struct wl_callback *callback; + EGLSurface egl_surface; + uint32_t fs_method; +}; + +struct input { + struct display *display; + struct wl_input_device *input_device; + uint32_t modifiers; + int32_t x, y, sx, sy; + struct wl_list link; + struct window *keyboard_focus; +}; + +static const char *vert_shader_text = + "uniform mat4 rotation;\n" + "attribute vec4 pos;\n" + "attribute vec4 color;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = rotation * pos;\n" + " v_color = color;\n" + "}\n"; + +static const char *frag_shader_text = + "precision mediump float;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_FragColor = v_color;\n" + "}\n"; + +static void +handle_configure(void *data, struct wl_shell_surface *shell_surface, + uint32_t time, uint32_t edges, + int32_t width, int32_t height) +{ + struct window *window = data; + uint32_t ret; + static const EGLint surface_attribs[] = { + EGL_ALPHA_FORMAT, EGL_ALPHA_FORMAT_PRE, + EGL_NONE + }; + + if (window->fs_method != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT) + return; + + window->geometry.width = width; + window->geometry.height = height; + eglMakeCurrent(window->display->egl.dpy, NULL, + NULL, window->display->egl.ctx); + + if ( window->egl_surface ) { + eglDestroySurface(window->display->egl.dpy, window->egl_surface); + window->egl_surface = NULL; + } + if ( window->native ) { + wl_egl_window_destroy(window->native); + window->native = NULL; + } + + window->native = + wl_egl_window_create(window->surface, + window->geometry.width, + window->geometry.height); + + window->egl_surface = + eglCreateWindowSurface(window->display->egl.dpy, + window->display->egl.conf, + window->native, + surface_attribs); + + ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface, + window->egl_surface, window->display->egl.ctx); + assert(ret == EGL_TRUE); + + glViewport(0, 0, window->geometry.width, window->geometry.height); + redraw(window, NULL, 0); +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_configure, +}; + +static void +destroy_surface(struct window *window) +{ + wl_egl_window_destroy(window->native); + + wl_shell_surface_destroy(window->shell_surface); + wl_surface_destroy(window->surface); + + if (window->callback) + wl_callback_destroy(window->callback); +} +static void +init_egl(struct display *display) +{ + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + static const EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_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_ES2_BIT, + EGL_NONE + }; + + EGLint major, minor, n; + EGLBoolean ret; + + display->egl.dpy = eglGetDisplay(display->display); + assert(display->egl.dpy); + + ret = eglInitialize(display->egl.dpy, &major, &minor); + assert(ret == EGL_TRUE); + ret = eglBindAPI(EGL_OPENGL_ES_API); + assert(ret == EGL_TRUE); + + assert(eglChooseConfig(display->egl.dpy, config_attribs, + &display->egl.conf, 1, &n) && n == 1); + + display->egl.ctx = eglCreateContext(display->egl.dpy, + display->egl.conf, + EGL_NO_CONTEXT, context_attribs); + assert(display->egl.ctx); +} + +static GLuint +create_shader(struct window *window, const char *source, GLenum shader_type) +{ + GLuint shader; + GLint status; + + shader = glCreateShader(shader_type); + assert(shader != 0); + + glShaderSource(shader, 1, (const char **) &source, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetShaderInfoLog(shader, 1000, &len, log); + fprintf(stderr, "Error: compiling %s: %*s\n", + shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment", + len, log); + exit(1); + } + + return shader; +} + +static void +init_gl(struct window *window) +{ + GLuint frag, vert; + GLint status; + + glViewport(0, 0, window->geometry.width, window->geometry.height); + + frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER); + vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER); + + window->gl.program = glCreateProgram(); + glAttachShader(window->gl.program, frag); + glAttachShader(window->gl.program, vert); + glLinkProgram(window->gl.program); + + glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status); + if (!status) { + char log[1000]; + GLsizei len; + glGetProgramInfoLog(window->gl.program, 1000, &len, log); + fprintf(stderr, "Error: linking:\n%*s\n", len, log); + exit(1); + } + + glUseProgram(window->gl.program); + + window->gl.pos = 0; + window->gl.pos = 1; + + glBindAttribLocation(window->gl.program, window->gl.pos, "pos"); + glBindAttribLocation(window->gl.program, window->gl.col, "color"); + glLinkProgram(window->gl.program); + + window->gl.rotation_uniform = + glGetUniformLocation(window->gl.program, "rotation"); +} + +static void +create_surface(struct window *window) +{ + struct display *display = window->display; + EGLBoolean ret; + static const EGLint surface_attribs[] = { + EGL_ALPHA_FORMAT, EGL_ALPHA_FORMAT_PRE, + EGL_NONE + }; + + window->surface = wl_compositor_create_surface(display->compositor); + wl_surface_set_user_data(window->surface, window); + window->shell_surface = wl_shell_get_shell_surface(display->shell, + window->surface); + wl_shell_surface_set_user_data(window->shell_surface, window); + window->native = + wl_egl_window_create(window->surface, + window->geometry.width, + window->geometry.height); + window->egl_surface = + eglCreateWindowSurface(display->egl.dpy, + display->egl.conf, + window->native, + surface_attribs); + + wl_shell_surface_add_listener(window->shell_surface, + &shell_surface_listener, window); + + wl_shell_surface_set_toplevel(window->shell_surface); + + ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface, + window->egl_surface, window->display->egl.ctx); + assert(ret == EGL_TRUE); +} + +static const struct wl_callback_listener frame_listener; + +static void +redraw(void *data, struct wl_callback *callback, uint32_t time) +{ + struct window *window = data; + static const GLfloat verts[4][2] = { + { -1, -1 }, + { 1, -1 }, + { 1, 1 }, + { -1, 1 } + }; + static const GLfloat colors[4][3] = { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 1, 1 }, + { 0, 0, 1 } + }; + GLfloat angle; + GLfloat rotation[4][4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + /*static const int32_t speed_div = 5;*/ + static uint32_t start_time = 0; + + if (start_time == 0) + start_time = time; + + /*angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;*/ + angle = 0; + rotation[0][0] = cos(angle); + rotation[0][2] = sin(angle); + rotation[2][0] = -sin(angle); + rotation[2][2] = cos(angle); + + glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE, + (GLfloat *) rotation); + + glClearColor(0.0, 0.0, 0.0, 0.5); + glClear(GL_COLOR_BUFFER_BIT); + + glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors); + glEnableVertexAttribArray(window->gl.pos); + glEnableVertexAttribArray(window->gl.col); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glDisableVertexAttribArray(window->gl.pos); + glDisableVertexAttribArray(window->gl.col); + + glFlush(); + + eglSwapBuffers(window->display->egl.dpy, window->egl_surface); + if (callback) + wl_callback_destroy(callback); + window->callback = wl_surface_frame(window->surface); + wl_callback_add_listener(window->callback, &frame_listener, window); +} + +static const struct wl_callback_listener frame_listener = { + redraw +}; + +#define FRAMERATE 0 +static void +key_handler(struct input *input, uint32_t time, + uint32_t key, uint32_t sym, uint32_t state) +{ + struct window *window = input->keyboard_focus; + uint32_t modifiers = input->modifiers; + + if ((modifiers & XKB_COMMON_CONTROL_MASK) && + (modifiers & XKB_COMMON_SHIFT_MASK) && + state) + return; + + fprintf(stderr, "key press\n"); + switch (sym) { + case XK_F12: + if (!state) + break; + window->fs_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; + wl_shell_surface_set_fullscreen(window->shell_surface, + window->fs_method, + FRAMERATE, + window->display->output); + break; + case XK_F11: + if (!state) + break; + window->fs_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE; + wl_shell_surface_set_fullscreen(window->shell_surface, + window->fs_method, + FRAMERATE, + window->display->output); + break; + case XK_F10: + if (!state) + break; + window->fs_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER; + wl_shell_surface_set_fullscreen(window->shell_surface, + window->fs_method, + FRAMERATE, + window->display->output); + break; + case XK_F9: + if (!state) + break; + window->fs_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL; + wl_shell_surface_set_fullscreen(window->shell_surface, + window->fs_method, + FRAMERATE, + window->display->output); + break; + case XK_F7: + if (!state) + break; + window->fs_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; + wl_shell_surface_set_toplevel(window->shell_surface); + handle_configure(window, NULL, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + break; + default: + break; + } +} + +static void +handle_key(void *data, struct wl_input_device *input_device, + uint32_t time, uint32_t key, uint32_t state) +{ + struct input *input = data; + struct window *window = input->keyboard_focus; + struct display *d = input->display; + uint32_t code, sym, level; + + code = key + d->xkb->min_key_code; + if (!window) + return; + + level = 0; + if (input->modifiers & XKB_COMMON_SHIFT_MASK && + XkbKeyGroupWidth(d->xkb, code, 0) > 1) + level = 1; + + sym = XkbKeySymEntry(d->xkb, code, level, 0); + + if (state) + input->modifiers |= d->xkb->map->modmap[code]; + else + input->modifiers &= ~d->xkb->map->modmap[code]; + + key_handler(input, time, key, sym, state); +} + +static void +handle_keyboard_focus(void *data, + struct wl_input_device *input_device, + uint32_t time, + struct wl_surface *surface, + struct wl_array *keys) +{ + struct input *input = data; + struct display *d = input->display; + uint32_t *k, *end; + + if (surface) + input->keyboard_focus = wl_surface_get_user_data(surface); + else + input->keyboard_focus = NULL; + + end = keys->data + keys->size; + input->modifiers = 0; + for (k = keys->data; k < end; k++) + input->modifiers |= d->xkb->map->modmap[*k]; +} + +static void +fake_handle_motion(void *data, struct wl_input_device *input_device, + uint32_t time, + int32_t x, int32_t y, int32_t sx, int32_t sy) +{ + printf ("%s: fake function\n", __FUNCTION__); +} + +static void +fake_handle_button(void *data, + struct wl_input_device *input_device, + uint32_t time, uint32_t button, uint32_t state) +{ + printf ("%s: fake function\n", __FUNCTION__); +} + +static void +fake_handle_pointer_focus(void *data, + struct wl_input_device *input_device, + uint32_t time, struct wl_surface *surface, + int32_t x, int32_t y, int32_t sx, int32_t sy) +{ + printf ("%s: fake function\n", __FUNCTION__); +} + +static const struct wl_input_device_listener input_device_listener = { + fake_handle_motion, + fake_handle_button, + handle_key, + fake_handle_pointer_focus, + handle_keyboard_focus, +}; + + +static void +display_add_input(struct display *d, uint32_t id) +{ + struct input *input; + + input = malloc(sizeof *input); + if (input == NULL) + return; + + memset(input, 0, sizeof *input); + input->display = d; + input->input_device = + wl_display_bind(d->display, id, &wl_input_device_interface); + + wl_input_device_add_listener(input->input_device, + &input_device_listener, input); + wl_input_device_set_user_data(input->input_device, input); +} + +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->compositor = + wl_display_bind(display, id, &wl_compositor_interface); + } else if (strcmp(interface, "wl_input_device") == 0) { + display_add_input(d, id); + } else if (strcmp(interface, "wl_shell") == 0) { + d->shell = wl_display_bind(display, id, &wl_shell_interface); + } else if (strcmp(interface, "wl_output") == 0) { + d->output = wl_display_bind(display, id, &wl_output_interface); + } +} + +static int +event_mask_update(uint32_t mask, void *data) +{ + struct display *d = data; + + d->mask = mask; + + return 0; +} + +const char *option_xkb_layout = "us"; +const char *option_xkb_variant = ""; +const char *option_xkb_options = ""; + +static const GOptionEntry xkb_option_entries[] = { + { "xkb-layout", 0, 0, G_OPTION_ARG_STRING, + &option_xkb_layout, "XKB Layout" }, + { "xkb-variant", 0, 0, G_OPTION_ARG_STRING, + &option_xkb_variant, "XKB Variant" }, + { "xkb-options", 0, 0, G_OPTION_ARG_STRING, + &option_xkb_options, "XKB Options" }, + { NULL } +}; + + + +static void +init_xkb(struct display *d) +{ + struct xkb_rule_names names; + + names.rules = "evdev"; + names.model = "pc105"; + names.layout = option_xkb_layout; + names.variant = option_xkb_variant; + names.options = option_xkb_options; + + d->xkb = xkb_compile_keymap_from_rules(&names); + if (!d->xkb) { + fprintf(stderr, "Failed to compile keymap\n"); + exit(1); + } +} + +static int running = 1; + +static void +signal_int(int signum) +{ + running = 0; +} + +static void +fini_egl(struct display *display) +{ + /* Required, otherwise segfault in egl_dri2.c: dri2_make_current() + * on eglReleaseThread(). */ + eglMakeCurrent(display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + eglTerminate(display->egl.dpy); + eglReleaseThread(); +} + +int +main(int argc, char **argv) +{ + struct sigaction sigint; + struct display display = { 0 }; + struct window window = { 0 }; + + memset(&display, 0, sizeof display); + memset(&window, 0, sizeof window); + + window.display = &display; + window.geometry.width = WINDOW_WIDTH; + window.geometry.height = WINDOW_HEIGHT; + + init_xkb(&display); + display.display = wl_display_connect(NULL); + assert(display.display); + + wl_display_add_global_listener(display.display, + display_handle_global, &display); + + wl_display_get_fd(display.display, event_mask_update, &display); + wl_display_iterate(display.display, WL_DISPLAY_READABLE); + + init_egl(&display); + create_surface(&window); + init_gl(&window); + + redraw(&window, NULL, 0); + + sigint.sa_handler = signal_int; + sigemptyset(&sigint.sa_mask); + sigint.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sigint, NULL); + + while (running) + wl_display_iterate(display.display, display.mask); + + fprintf(stderr, "simple-rect exiting\n"); + + destroy_surface(&window); + fini_egl(&display); + + if (display.shell) + wl_shell_destroy(display.shell); + + if (display.compositor) + wl_compositor_destroy(display.compositor); + + wl_display_flush(display.display); + wl_display_destroy(display.display); + + return 0; +} -- 1.7.5.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel