diff --git a/.gitignore b/.gitignore index cafab323..576f5602 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ *.so glx-compositor egl-compositor -window +gears +terminal flower screenshot *.jpg diff --git a/Makefile.in b/Makefile.in index 5967062e..da1e9904 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ CFLAGS = @GCC_CFLAGS@ libs = libwayland-server.so libwayland.so -clients = flower window screenshot +clients = flower gears screenshot terminal compositors = egl-compositor glx-compositor all : $(libs) $(compositors) $(clients) @@ -38,8 +38,9 @@ glx-compositor : CFLAGS += @GL_COMPOSITOR_CFLAGS@ glx-compositor : LDLIBS += @GL_COMPOSITOR_LIBS@ -L. -lwayland-server flower : flower.o wayland-glib.o cairo-util.o -window : window.o gears.o wayland-glib.o cairo-util.o +gears : gears.o window.o wayland-glib.o cairo-util.o screenshot : screenshot.o wayland-glib.o +terminal : terminal.o window.o wayland-glib.o cairo-util.o $(clients) : CFLAGS += @CLIENT_CFLAGS@ $(clients) : LDLIBS += @CLIENT_LIBS@ -L. -lwayland -lrt diff --git a/gears.c b/gears.c index 21ab602d..6310479f 100644 --- a/gears.c +++ b/gears.c @@ -1,47 +1,104 @@ /* - * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * Copyright © 2008 Kristian Høgsberg + * + * 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 +#include #include +#include +#include +#include #include +#include +#include +#include + #include -#include "gears.h" +#include + +#include "wayland-client.h" +#include "wayland-glib.h" + +#include "cairo-util.h" +#include "window.h" + +static const char gem_device[] = "/dev/dri/card0"; +static const char socket_name[] = "\0wayland"; struct gears { - GLint gear1, gear2, gear3; + struct window *window; + + struct wl_display *wl_display; + struct rectangle rectangle; + + EGLDisplay display; + EGLConfig config; + EGLSurface surface; + EGLContext context; + int resized; + int fd; + GLfloat angle; + struct buffer *buffer; + + GLint gear_list[3]; }; +struct gear_template { + GLfloat material[4]; + GLfloat inner_radius; + GLfloat outer_radius; + GLfloat width; + GLint teeth; + GLfloat tooth_depth; +}; + +const static struct gear_template gear_templates[] = { + { { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 }, + { { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 }, + { { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 }, +}; + +static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0}; + +static void die(const char *msg) +{ + fprintf(stderr, "%s", msg); + exit(EXIT_FAILURE); +} + static void -gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, - GLint teeth, GLfloat tooth_depth) +make_gear(const struct gear_template *t) { GLint i; GLfloat r0, r1, r2; GLfloat angle, da; GLfloat u, v, len; - r0 = inner_radius; - r1 = outer_radius - tooth_depth / 2.0; - r2 = outer_radius + tooth_depth / 2.0; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material); - da = 2.0 * M_PI / teeth / 4.0; + r0 = t->inner_radius; + r1 = t->outer_radius - t->tooth_depth / 2.0; + r2 = t->outer_radius + t->tooth_depth / 2.0; + + da = 2.0 * M_PI / t->teeth / 4.0; glShadeModel(GL_FLAT); @@ -49,27 +106,27 @@ gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, /* draw front face */ glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); - glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); - if (i < teeth) { - glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + for (i = 0; i <= t->teeth; i++) { + angle = i * 2.0 * M_PI / t->teeth; + glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5); + if (i < t->teeth) { + glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5); } } glEnd(); /* draw front sides of teeth */ glBegin(GL_QUADS); - da = 2.0 * M_PI / teeth / 4.0; - for (i = 0; i < teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - - glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + da = 2.0 * M_PI / t->teeth / 4.0; + for (i = 0; i < t->teeth; i++) { + angle = i * 2.0 * M_PI / t->teeth; + + glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5); } glEnd(); @@ -77,58 +134,58 @@ gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, /* draw back face */ glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); - if (i < teeth) { - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + for (i = 0; i <= t->teeth; i++) { + angle = i * 2.0 * M_PI / t->teeth; + glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5); + if (i < t->teeth) { + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5); } } glEnd(); /* draw back sides of teeth */ glBegin(GL_QUADS); - da = 2.0 * M_PI / teeth / 4.0; - for (i = 0; i < teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); - glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + da = 2.0 * M_PI / t->teeth / 4.0; + for (i = 0; i < t->teeth; i++) { + angle = i * 2.0 * M_PI / t->teeth; + + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5); } glEnd(); /* draw outward faces of teeth */ glBegin(GL_QUAD_STRIP); - for (i = 0; i < teeth; i++) { - angle = i * 2.0 * M_PI / teeth; + for (i = 0; i < t->teeth; i++) { + angle = i * 2.0 * M_PI / t->teeth; - glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); - glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5); u = r2 * cos(angle + da) - r1 * cos(angle); v = r2 * sin(angle + da) - r1 * sin(angle); len = sqrt(u * u + v * v); u /= len; v /= len; glNormal3f(v, -u, 0.0); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5); glNormal3f(cos(angle), sin(angle), 0.0); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5); u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); glNormal3f(v, -u, 0.0); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5); glNormal3f(cos(angle), sin(angle), 0.0); } - glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); - glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); + glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5); + glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5); glEnd(); @@ -136,71 +193,17 @@ gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, /* draw inside radius cylinder */ glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0 * M_PI / teeth; + for (i = 0; i <= t->teeth; i++) { + angle = i * 2.0 * M_PI / t->teeth; glNormal3f(-cos(angle), -sin(angle), 0.0); - glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5); } glEnd(); } -struct gears * -gears_create(GLfloat clear_red, GLfloat clear_green, - GLfloat clear_blue, GLfloat clear_alpha) -{ - static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0}; - static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0}; - static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0}; - static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0}; - struct gears *gears; - - gears = malloc(sizeof *gears); - /* make the gears */ - gears->gear1 = glGenLists(1); - glNewList(gears->gear1, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); - gear(1.0, 4.0, 1.0, 20, 0.7); - glEndList(); - - gears->gear2 = glGenLists(1); - glNewList(gears->gear2, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); - gear(0.5, 2.0, 2.0, 10, 0.7); - glEndList(); - - gears->gear3 = glGenLists(1); - glNewList(gears->gear3, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); - gear(1.3, 2.0, 0.5, 10, 0.7); - glEndList(); - - glEnable(GL_NORMALIZE); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0); - glMatrixMode(GL_MODELVIEW); - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - - /* We're generating premultiplied alpha so multiply in the - * alpha. The gears are solid color and doesn't have - * anti-aliased edges, they're ok. */ - glClearColor(clear_red * clear_alpha, - clear_green * clear_alpha, - clear_blue * clear_alpha, - clear_alpha); - - return gears; -} - -void -gears_draw(struct gears *gears, GLfloat angle) +static void +draw_gears(struct gears *gears) { GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; @@ -216,24 +219,194 @@ gears_draw(struct gears *gears, GLfloat angle) glPushMatrix(); glTranslatef(-3.0, -2.0, 0.0); - glRotatef(angle, 0.0, 0.0, 1.0); - glCallList(gears->gear1); + glRotatef(gears->angle, 0.0, 0.0, 1.0); + glCallList(gears->gear_list[0]); glPopMatrix(); glPushMatrix(); glTranslatef(3.1, -2.0, 0.0); - glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); - glCallList(gears->gear2); + glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0); + glCallList(gears->gear_list[1]); glPopMatrix(); - glPushMatrix(); glTranslatef(-3.1, 4.2, 0.0); - glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); - glCallList(gears->gear3); + glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0); + glCallList(gears->gear_list[2]); glPopMatrix(); glPopMatrix(); glFlush(); } + +static void +resize_window(struct gears *gears) +{ + window_draw(gears->window); + window_get_child_rectangle(gears->window, &gears->rectangle); + + if (gears->buffer != NULL) + buffer_destroy(gears->buffer, gears->fd); + + gears->buffer = buffer_create(gears->fd, + gears->rectangle.width, + gears->rectangle.height, + (gears->rectangle.width * 4 + 15) & ~15); + + gears->surface = eglCreateSurfaceForName(gears->display, + gears->config, + gears->buffer->name, + gears->buffer->width, + gears->buffer->height, + gears->buffer->stride, NULL); + + eglMakeCurrent(gears->display, + gears->surface, gears->surface, gears->context); + + glViewport(0, 0, gears->rectangle.width, gears->rectangle.height); + gears->resized = 0; +} + +static void +resize_handler(struct window *window, int32_t width, int32_t height, void *data) +{ + struct gears *gears = data; + + /* Right now, resizing the window from the per-frame callback + * is fine, since the window drawing code is so slow that we + * can't draw more than one window per frame anyway. However, + * once we implement faster resizing, this will show lag + * between pointer motion and window size even if resizing is + * fast. We need to keep processing motion events and posting + * new frames as fast as possible so when the server + * composites the next frame it will have the most recent size + * possible, like what we do for window moves. */ + + gears->resized = 1; +} + +static void +acknowledge_handler(struct window *window, uint32_t key, void *data) +{ + struct gears *gears = data; + + if (key != 0) + return; + + if (gears->resized) + resize_window(gears); + + draw_gears(gears); +} + +static void +frame_handler(struct window *window, uint32_t frame, uint32_t timestamp, void *data) +{ + struct gears *gears = data; + + window_copy(gears->window, + &gears->rectangle, + gears->buffer->name, gears->buffer->stride); + + wl_display_commit(gears->wl_display, 0); + + gears->angle += 1; +} + +static struct gears * +gears_create(struct wl_display *display, int fd) +{ + const int x = 200, y = 200, width = 450, height = 500; + EGLint major, minor, count; + EGLConfig configs[64]; + struct gears *gears; + int i; + + gears = malloc(sizeof *gears); + memset(gears, 0, sizeof *gears); + gears->wl_display = display; + gears->fd = fd; + gears->window = window_create(display, fd, "Wayland Gears", + x, y, width, height); + + gears->display = eglCreateDisplayNative("/dev/dri/card0", "i965"); + if (gears->display == NULL) + die("failed to create egl display\n"); + + if (!eglInitialize(gears->display, &major, &minor)) + die("failed to initialize display\n"); + + if (!eglGetConfigs(gears->display, configs, 64, &count)) + die("failed to get configs\n"); + + gears->config = configs[24]; + gears->context = eglCreateContext(gears->display, gears->config, NULL, NULL); + if (gears->context == NULL) + die("failed to create context\n"); + + resize_window(gears); + + for (i = 0; i < 3; i++) { + gears->gear_list[i] = glGenLists(1); + glNewList(gears->gear_list[i], GL_COMPILE); + make_gear(&gear_templates[i]); + glEndList(); + } + + glEnable(GL_NORMALIZE); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0); + glMatrixMode(GL_MODELVIEW); + + glLightfv(GL_LIGHT0, GL_POSITION, light_pos); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + glClearColor(0, 0, 0, 0.92); + + draw_gears(gears); + gears->angle += 1; + + frame_handler(gears->window, 0, 0, gears); + + window_set_resize_handler(gears->window, resize_handler, gears); + window_set_frame_handler(gears->window, frame_handler, gears); + window_set_acknowledge_handler(gears->window, acknowledge_handler, gears); + + return gears; +} + +int main(int argc, char *argv[]) +{ + struct wl_display *display; + int fd; + GMainLoop *loop; + GSource *source; + struct gears *gears; + + fd = open(gem_device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "drm open failed: %m\n"); + return -1; + } + + display = wl_display_create(socket_name, sizeof socket_name); + if (display == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + return -1; + } + + loop = g_main_loop_new(NULL, FALSE); + source = wl_glib_source_new(display); + g_source_attach(source, NULL); + + gears = gears_create(display, fd); + + g_main_loop_run(loop); + + return 0; +} diff --git a/gears.h b/gears.h deleted file mode 100644 index 52250c5b..00000000 --- a/gears.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _GEARS_H_ -#define _GEARS_H_ - -struct gears; - -struct gears *gears_create(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); - -void gears_draw(struct gears *gears, GLfloat angle); - -#endif diff --git a/terminal.c b/terminal.c new file mode 100644 index 00000000..e029d9bb --- /dev/null +++ b/terminal.c @@ -0,0 +1,133 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "wayland-client.h" +#include "wayland-glib.h" + +#include "cairo-util.h" +#include "window.h" + +static const char gem_device[] = "/dev/dri/card0"; +static const char socket_name[] = "\0wayland"; + +struct terminal { + struct window *window; + struct wl_display *display; + int resize_scheduled; +}; + +static gboolean +resize_window(void *data) +{ + struct terminal *terminal = data; + + window_draw(terminal->window); + wl_display_commit(terminal->display, 0); + + return FALSE; +} + +static void +resize_handler(struct window *window, int32_t width, int32_t height, void *data) +{ + struct terminal *terminal = data; + + if (!terminal->resize_scheduled) { + g_idle_add(resize_window, terminal); + terminal->resize_scheduled = 1; + } +} + +static void +acknowledge_handler(struct window *window, uint32_t key, void *data) +{ + struct terminal *terminal = data; + + terminal->resize_scheduled = 0; +} + +static struct terminal * +terminal_create(struct wl_display *display, int fd) +{ + struct terminal *terminal; + + terminal = malloc(sizeof *terminal); + if (terminal == NULL) + return terminal; + + terminal->window = window_create(display, fd, "Wayland Terminal", + 500, 100, 300, 200); + terminal->display = display; + terminal->resize_scheduled = 1; + + window_set_resize_handler(terminal->window, resize_handler, terminal); + window_set_acknowledge_handler(terminal->window, acknowledge_handler, terminal); + + return terminal; +} + +int main(int argc, char *argv[]) +{ + struct wl_display *display; + int fd; + GMainLoop *loop; + GSource *source; + struct terminal *terminal; + + fd = open(gem_device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "drm open failed: %m\n"); + return -1; + } + + display = wl_display_create(socket_name, sizeof socket_name); + if (display == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + return -1; + } + + loop = g_main_loop_new(NULL, FALSE); + source = wl_glib_source_new(display); + g_source_attach(source, NULL); + + terminal = terminal_create(display, fd); + window_draw(terminal->window); + wl_display_commit(display, 0); + + g_main_loop_run(loop); + + return 0; +} diff --git a/window.c b/window.c index 63c49b9b..4f4b7046 100644 --- a/window.c +++ b/window.c @@ -31,45 +31,31 @@ #include #include -#include -#include - #include "wayland-client.h" #include "wayland-glib.h" -#include "gears.h" #include "cairo-util.h" -static const char gem_device[] = "/dev/dri/card0"; -static const char socket_name[] = "\0wayland"; - -static void die(const char *msg) -{ - fprintf(stderr, "%s", msg); - exit(EXIT_FAILURE); -} +#include "window.h" struct window { struct wl_display *display; struct wl_surface *surface; + const char *title; int x, y, width, height; + int minimum_width, minimum_height; int margin; int drag_x, drag_y, last_x, last_y; int state; uint32_t name; int fd; - int resized; - cairo_pattern_t *background; struct buffer *buffer; - struct buffer *egl_buffer; - - GLfloat gears_angle; - struct gears *gears; - EGLDisplay egl_display; - EGLContext context; - EGLConfig config; - EGLSurface egl_surface; + + window_resize_handler_t resize_handler; + window_frame_handler_t frame_handler; + window_acknowledge_handler_t acknowledge_handler; + void *user_data; }; static void @@ -86,18 +72,14 @@ rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius) cairo_close_path(cr); } -static gboolean -draw_window(void *data) +void +window_draw(struct window *window) { - struct window *window = data; cairo_surface_t *surface; cairo_t *cr; int border = 2, radius = 5; cairo_text_extents_t extents; cairo_pattern_t *gradient, *outline, *bright, *dim; - const static char title[] = "Wayland First Post"; - struct buffer *buffer; - int width, height; surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, window->width + window->margin * 2, @@ -155,12 +137,12 @@ draw_window(void *data) cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_set_font_size(cr, 14); - cairo_text_extents(cr, title, &extents); + cairo_text_extents(cr, window->title, &extents); cairo_move_to(cr, (window->width - extents.width) / 2, 10 - extents.y_bearing); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); cairo_set_line_width (cr, 4); - cairo_text_path(cr, title); + cairo_text_path(cr, window->title); cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); @@ -181,23 +163,6 @@ draw_window(void *data) window->y - window->margin, window->width + 2 * window->margin, window->height + 2 * window->margin); - - width = window->width - 20; - height = window->height - 60; - buffer = buffer_create(window->fd, width, height, (width * 4 + 15) & ~15); - window->egl_buffer = buffer; - window->egl_surface = eglCreateSurfaceForName(window->egl_display, - window->config, buffer->name, - buffer->width, buffer->height, - buffer->stride, NULL); - if (!eglMakeCurrent(window->egl_display, - window->egl_surface, window->egl_surface, window->context)) - die("failed to make context current\n"); - - glViewport(0, 0, width, height); - window->resized = 0; - - return FALSE; } enum window_state { @@ -218,25 +183,12 @@ enum location { LOCATION_OUTSIDE }; -static int -update_gears(void *data) -{ - struct window *window = data; - - if (window->resized) - draw_window(window); - gears_draw(window->gears, window->gears_angle); - - return FALSE; -} - static void event_handler(struct wl_display *display, uint32_t object, uint32_t opcode, uint32_t size, uint32_t *p, void *data) { struct window *window = data; - struct buffer *buffer; int location; int grip_size = 16; @@ -258,20 +210,18 @@ event_handler(struct wl_display *display, buffer_destroy(window->buffer, window->fd); window->buffer = NULL; } - g_idle_add(update_gears, window); + if (window->acknowledge_handler) + (*window->acknowledge_handler)(window, key, + window->user_data); + } else if (object == 1 && opcode == 4) { /* The frame event means that the previous frame was * composited, and we can now send the request to copy * the frame we've rendered in the mean time into the * servers surface buffer. */ - buffer = window->egl_buffer; - wl_surface_copy(window->surface, - 10 + window->margin, 50 + window->margin, - buffer->name, buffer->stride, - 0, 0, buffer->width, buffer->height); - wl_display_commit(window->display, 0); - window->gears_angle += 1; - + if (window->frame_handler) + (*window->frame_handler)(window, p[0], p[1], + window->user_data); } else if (object == 1) { fprintf(stderr, "unexpected event from display: %d\n", opcode); @@ -295,26 +245,16 @@ event_handler(struct wl_display *display, case WINDOW_RESIZING_LOWER_RIGHT: window->width = window->drag_x + x; window->height = window->drag_y + y; - if (window->width < 400) - window->width = 400; - if (window->height < 400) - window->height = 400; - - /* Right now, resizing the window from the - * per-frame callback is fine, since the - * window drawing code is so slow that we - * can't draw more than one window per frame - * anyway. However, once we implement faster - * resizing, this will show lag between - * pointer motion and window size even if - * resizing is fast. We need to keep - * processing motion events and posting new - * frames as fast as possible so when the - * server composites the next frame it will - * have the most recent size possible, like - * what we do for window moves. */ - - window->resized = 1; + if (window->width < window->minimum_width) + window->width = window->minimum_width; + if (window->height < window->minimum_height) + window->height = window->minimum_height; + + if (window->resize_handler) + (*window->resize_handler)(window, + window->width, + window->height, + window->user_data); break; } } else if (opcode == 1) { @@ -356,13 +296,65 @@ event_handler(struct wl_display *display, } } -static struct window * -window_create(struct wl_display *display, int fd) +void +window_get_child_rectangle(struct window *window, + struct rectangle *rectangle) +{ + rectangle->x = 10; + rectangle->y = 50; + rectangle->width = window->width - 20; + rectangle->height = window->height - 60; +} + +void +window_copy(struct window *window, + struct rectangle *rectangle, + uint32_t name, uint32_t stride) +{ + wl_surface_copy(window->surface, + window->margin + rectangle->x, + window->margin + rectangle->y, + name, stride, + 0, 0, rectangle->width, rectangle->height); +} + +void +window_set_resize_handler(struct window *window, + window_resize_handler_t handler, void *data) +{ + window->resize_handler = handler; + window->user_data = data; +} + +void +window_set_frame_handler(struct window *window, + window_frame_handler_t handler, void *data) +{ + window->frame_handler = handler; + window->user_data = data; +} + +void +window_set_acknowledge_handler(struct window *window, + window_acknowledge_handler_t handler, void *data) +{ + window->acknowledge_handler = handler; + window->user_data = data; +} + +void +window_set_minimum_size(struct window *window, uint32_t width, int32_t height) +{ + window->minimum_width = width; + window->minimum_height = height; +} + +struct window * +window_create(struct wl_display *display, int fd, + const char *title, + int32_t x, int32_t y, int32_t width, int32_t height) { - EGLint major, minor, count; - EGLConfig configs[64]; struct window *window; - const GLfloat red = 0, green = 0, blue = 0, alpha = 0.92; window = malloc(sizeof *window); if (window == NULL) @@ -370,69 +362,19 @@ window_create(struct wl_display *display, int fd) memset(window, 0, sizeof *window); window->display = display; + window->title = strdup(title); window->surface = wl_display_create_surface(display); - window->x = 200; - window->y = 200; - window->width = 450; - window->height = 500; + window->x = x; + window->y = y; + window->minimum_width = 100; + window->minimum_height = 100; + window->width = width; + window->height = height; window->margin = 16; window->state = WINDOW_STABLE; window->fd = fd; - window->background = cairo_pattern_create_rgba (red, green, blue, alpha); - - window->egl_display = eglCreateDisplayNative("/dev/dri/card0", "i965"); - if (window->egl_display == NULL) - die("failed to create egl display\n"); - - if (!eglInitialize(window->egl_display, &major, &minor)) - die("failed to initialize display\n"); - - if (!eglGetConfigs(window->egl_display, configs, 64, &count)) - die("failed to get configs\n"); - - window->config = configs[24]; - window->context = eglCreateContext(window->egl_display, window->config, NULL, NULL); - if (window->context == NULL) - die("failed to create context\n"); - - draw_window(window); - window->gears = gears_create(0, 0, 0, 0.92); - gears_draw(window->gears, window->gears_angle); - window->gears_angle += 1; - wl_display_commit(window->display, 0); - - return window; -} - -int main(int argc, char *argv[]) -{ - struct wl_display *display; - int fd; - struct window *window; - GMainLoop *loop; - GSource *source; - - fd = open(gem_device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "drm open failed: %m\n"); - return -1; - } - - display = wl_display_create(socket_name, sizeof socket_name); - if (display == NULL) { - fprintf(stderr, "failed to create display: %m\n"); - return -1; - } - - loop = g_main_loop_new(NULL, FALSE); - source = wl_glib_source_new(display); - g_source_attach(source, NULL); - - window = window_create(display, fd); wl_display_set_event_handler(display, event_handler, window); - g_main_loop_run(loop); - - return 0; + return window; } diff --git a/window.h b/window.h new file mode 100644 index 00000000..cf357878 --- /dev/null +++ b/window.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2008 Kristian Høgsberg + * + * 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. + */ + +#ifndef _WINDOW_H_ +#define _WINDOW_H_ + +struct window; + +struct rectangle { + int32_t x; + int32_t y; + int32_t width; + int32_t height; +}; + +typedef void (*window_resize_handler_t)(struct window *window, int32_t width, int32_t height, void *data); +typedef void (*window_frame_handler_t)(struct window *window, uint32_t frame, uint32_t timestamp, void *data); +typedef void (*window_acknowledge_handler_t)(struct window *window, uint32_t key, void *data); + +struct window * +window_create(struct wl_display *display, int fd, + const char *title, + int32_t x, int32_t y, int32_t width, int32_t height); + +void +window_set_minimum_size(struct window *window, uint32_t width, int32_t height); + +void +window_draw(struct window *window); +void +window_get_child_rectangle(struct window *window, + struct rectangle *rectangle); +void +window_copy(struct window *window, + struct rectangle *rectangle, + uint32_t name, uint32_t stride); + +void +window_set_resize_handler(struct window *window, + window_resize_handler_t handler, void *data); +void +window_set_frame_handler(struct window *window, + window_frame_handler_t handler, void *data); +void +window_set_acknowledge_handler(struct window *window, + window_acknowledge_handler_t handler, void *data); + +#endif