Refactor window logic into reusable parts, add a new terminal application.
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.
diff --git a/window.c b/window.c
index 63c49b9..4f4b704 100644
--- a/window.c
+++ b/window.c
@@ -31,45 +31,31 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
+ if (window->width < window->minimum_width)
+ window->width = window->minimum_width;
+ if (window->height < window->minimum_height)
+ window->height = window->minimum_height;
- /* 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->resize_handler)
+ (*window->resize_handler)(window,
+ window->width,
+ window->height,
+ window->user_data);
break;
}
} else if (opcode == 1) {
@@ -356,13 +296,65 @@
}
}
-static struct window *
-window_create(struct wl_display *display, int fd)
+void
+window_get_child_rectangle(struct window *window,
+ struct rectangle *rectangle)
{
- EGLint major, minor, count;
- EGLConfig configs[64];
+ 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)
+{
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 @@
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;
}