Refactor window logic into reusable parts, add a new terminal application.
authorKristian Høgsberg <krh@redhat.com>
Mon, 8 Dec 2008 00:59:11 +0000 (19:59 -0500)
committerKristian Høgsberg <krh@redhat.com>
Mon, 8 Dec 2008 01:05:36 +0000 (20:05 -0500)
The gears code is moved into a new file gearc.c and the window decoration
and management code stays in window.c.  A new application 'terminal' is the
second user of the windowing code, but doesn't do anything useful yet.

.gitignore
Makefile.in
gears.c
gears.h [deleted file]
terminal.c [new file with mode: 0644]
window.c
window.h [new file with mode: 0644]

index cafab32..576f560 100644 (file)
@@ -2,7 +2,8 @@
 *.so
 glx-compositor
 egl-compositor
-window
+gears
+terminal
 flower
 screenshot
 *.jpg
index 5967062..da1e990 100644 (file)
@@ -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 21ab602..6310479 100644 (file)
--- a/gears.c
+++ b/gears.c
 /*
- * 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 <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <math.h>
+#include <time.h>
+#include <cairo.h>
+#include <glib.h>
+
 #include <GL/gl.h>
-#include "gears.h"
+#include <eagle.h>
+
+#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 (file)
index 52250c5..0000000
--- 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 (file)
index 0000000..e029d9b
--- /dev/null
@@ -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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <cairo.h>
+#include <glib.h>
+
+#include <GL/gl.h>
+#include <eagle.h>
+
+#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;
+}
index 63c49b9..4f4b704 100644 (file)
--- a/window.c
+++ b/window.c
 #include <cairo.h>
 #include <glib.h>
 
-#include <GL/gl.h>
-#include <eagle.h>
-
 #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 (file)
index 0000000..cf35787
--- /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