]> Pileus Git - wmpus/blobdiff - sys-xwl.c
Improve input handling
[wmpus] / sys-xwl.c
index 01d43b47c5e06bdd5e3287c92a4ecd45976e4779..312657b5302fca8dcc6f5f05ea46c355916458ef 100644 (file)
--- a/sys-xwl.c
+++ b/sys-xwl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Andy Spencer <andy753421@gmail.com>
+ * Copyright (c) 2014-2015 Andy Spencer <andy753421@gmail.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
 #include <sys/mman.h>
 
+#include <libevdev/libevdev.h>
 #include <xkbcommon/xkbcommon.h>
 #include <wayland-server.h>
 #include <wayland-client.h>
 #include "sys.h"
 #include "wm.h"
 
-/* Internal structures */
-struct win_sys {
-       win_t *win;
-};
+#include "xdg-shell-client-protocol.h"
+#include "xdg-shell-server-protocol.h"
+#include "gtk-shell-client-protocol.h"
+#include "gtk-shell-server-protocol.h"
 
+/* Window Managers calls */
+void wm_update(void);
+
+/* Wayland user data */
 typedef struct {
-       uint8_t *mem;
-       size_t   size;
+       uint8_t             *mem;
+       size_t               size;
 } sys_pool_t;
 
 typedef struct {
-       sys_pool_t      *pool;
-       uint8_t         *mem;
-       cairo_surface_t *surface;
-} sys_buf_t;
+       sys_pool_t          *pool;
+       uint8_t             *mem;
+       cairo_surface_t     *surface;
+} sys_bdata_t;
 
-struct wl_resource *output;
+typedef struct {
+       struct wl_client    *cli;
+       list_t              *ptrs;    // of struct wl_resource
+       list_t              *kbds;    // of struct wl_resource
+       list_t              *tchs;    // of struct wl_resource
+} sys_cdata_t;
 
-sys_pool_t *gdata[10];
-int         gidx;
+/* Internal structures */
+struct win_sys {
+       struct wl_resource  *sfc;
+       struct wl_resource  *ssfc;
+       struct wl_resource  *xsfc;
+       struct wl_resource  *buf;
+       sys_cdata_t         *cdata;
+       int                  x,y;     // surface x,y
+       int                  wx,wy;   // window  x,y inside sfc
+       int                  ww,wh;   // window  w,h inside sfc
+};
 
 /* Global data */
+static win_t                *root;    // root window
+static win_t                *hover;   // window the mouse is over
+static win_t                *focus;   // focused window
+static win_t                *cursor;  // mouse cursor image
+
+static list_t               *clients; // of sys_cdata_t
+static list_t               *windows; // of win_t
+
+static double                cursor_x;
+static double                cursor_y;
+static double                cursor_dx;
+static double                cursor_dy;
+
+static GtkWidget            *screen;
+
+static struct wl_resource   *output;
 static struct wl_display    *display;
 static struct wl_event_loop *events;
 
-static GtkWidget            *window;
-static sys_buf_t            *buffer;
+static struct wl_array       keys;
 
-/*****************
- * Gtk Callbacks *
- *****************/
+/* Constant data */
+static struct wl_array       xstate_normal;
+static struct wl_array       xstate_active;
+static struct wl_array       xstate_max;
+static struct wl_array       xstate_full;
+static struct wl_array       xstate_resize;
 
-static void on_destroy(GtkWidget *widget, GdkEvent *event, gpointer user_data)
-{
-       printf("on_destroy\n");
-       sys_exit();
-}
+/********************
+ * Helper Functions *
+ ********************/
 
-static gboolean on_key(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+static void set_array(struct wl_array *array, int n, ...)
 {
-       printf(g_ascii_isprint(event->keyval)
-               ? "on_key: '%c'\n"
-               : "on_key: 0x%X\n",
-               event->keyval);
-       if (event->keyval == GDK_KEY_q)
-               sys_exit();
-       if (event->keyval == GDK_KEY_t)
-               g_spawn_command_line_async("st-wl", NULL);
-       return TRUE;
+       va_list ap;
+       va_start(ap, n);
+       wl_array_init(array);
+       for (int i = 0; i < n; i++) {
+               uint32_t item = va_arg(ap, uint32_t);
+               uint32_t *ptr = wl_array_add(array, sizeof(item));
+               if (!ptr)
+                       error("Unable to allocate constant");
+               *ptr = item;
+       }
+       va_end(ap);
 }
 
-static gboolean on_button(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+static int get_serial(void)
 {
-       printf("on_button\n");
-       return TRUE;
+       static int serial = 0;
+       return serial++;
 }
 
-static gboolean on_move(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
+static int get_time(void)
 {
-       //printf("on_motion\n");
-       return TRUE;
-}
+       static uint64_t epoch;
 
-static gboolean on_draw(GtkWidget *widget, cairo_t *cairo, gpointer user_data)
-{
-       printf("on_draw\n");
+       struct timespec ts;
+       clock_gettime(CLOCK_REALTIME, &ts);
 
-       if (buffer) {
-               cairo_surface_mark_dirty(buffer->surface);
-               cairo_set_source_surface(cairo, buffer->surface, 10, 10);
-               cairo_paint(cairo);
-       }
+       uint64_t now = (((uint64_t)ts.tv_sec ) * 1000)
+                    + (((uint64_t)ts.tv_nsec) / 1000000);
 
-       cairo_set_source_rgb(cairo, 1, 1, 1);
-       cairo_arc(cairo, 150, 150, 50, 0, 2*G_PI);
-       cairo_fill(cairo);
-
-       //int gi = 0, mi;
-       //FILE *fd = fopen("/tmp/mem.txt", "w+");
-       //for (gi = 0; gi < 10; gi++) {
-       //      mi = 0;
-       //      while (gdata[gi] && (mi+32) < gdata[gi]->size) {
-       //              fprintf(fd, "%d %p %08x: ", gi, gdata[gi]->mem, mi);
-       //              for (int i = 0; i < 16; mi++, i += 2)
-       //                      fprintf(fd, "%02hhx%02hhx ",
-       //                              gdata[gi]->mem[mi+0],
-       //                              gdata[gi]->mem[mi+1]);
-       //              fprintf(fd, "\n");
-       //      }
-       //      fprintf(fd, "\n");
-       //}
-       //printf("\n");
-       //fclose(fd);
+       if (epoch == 0)
+               epoch = now;
 
-       return TRUE;
+       return (int)(now - epoch);
 }
 
-static gboolean on_wayland(gpointer user_data)
+static ptr_t get_ptr(win_t *win)
 {
-       // TODO - convert to polled execution
-       wl_display_flush_clients(display);
-       wl_event_loop_dispatch(events, 0);
-       return TRUE;
+       ptr_t ptr = {
+               .rx = cursor_x,
+               .ry = cursor_y,
+       };
+       if (win) {
+               ptr.x = cursor_x - win->x;
+               ptr.y = cursor_y - win->y;
+       };
+       return ptr;
 }
 
-/*********************
- * Wayland Callbacks *
- *********************/
+static mod_t get_mod(unsigned int state, int up)
+{
+       return (mod_t){
+              .alt   = !!(state & GDK_MOD1_MASK   ),
+              .ctrl  = !!(state & GDK_CONTROL_MASK),
+              .shift = !!(state & GDK_SHIFT_MASK  ),
+              .win   = !!(state & GDK_MOD4_MASK   ),
+              .up    = up,
+       };
+}
 
-#if 0
-static void new_window(void)
+static win_t *find_win(int x, int y)
 {
-       printf("new_window\n");
+       for (list_t *cur = windows; cur; cur = cur->next) {
+               win_t *win = cur->data;
+               printf("find_win -- %p -- %4d,%-4d : %4dx%-4d\n",
+                       win, win->x, win->y, win->w, win->h);
+       }
+       for (list_t *cur = windows; cur; cur = cur->next) {
+               win_t *win = cur->data;
+               int l = win->x;
+               int r = win->w + l;
+               int t = win->y;
+               int b = win->h + t;
+               if (l <= x && x <= r && t <= y && y <= b) {
+                       printf("find_win -> %p\n", win);
+                       return win;
+               }
+       }
+       return NULL;
 }
 
-static void new_screen(void)
+static sys_cdata_t *find_cdata(struct wl_client *cli)
 {
-       printf("new_screen\n");
+       // Search for existing client
+       for (list_t *cur = clients; cur; cur = cur->next) {
+               sys_cdata_t *cdata = cur->data;
+               if (cdata->cli == cli)
+                       return cdata;
+       }
+
+       // Not found, create new one
+       sys_cdata_t *cdata = new0(sys_cdata_t);
+       clients = list_insert(clients, cdata);
+       cdata->cli = cli;
+       return cdata;
 }
-#endif
 
 /****************************
  * Wayland Buffer Interface *
  ****************************/
+static void buffer_destroy(struct wl_client *cli, struct wl_resource *reso)
+{
+       printf("buffer_destroy\n");
+}
+
 static struct wl_buffer_interface buffer_iface = {
-        .destroy  = NULL,
+        .destroy  = buffer_destroy,
 };
 
 /***********************************
@@ -169,14 +226,14 @@ static void pool_create_buffer(struct wl_client *cli, struct wl_resource *pool,
                uint32_t id, int32_t offset, int32_t width, int32_t height,
                int32_t stride, uint32_t format)
 {
-       sys_buf_t  *buf  = new0(sys_buf_t);
-       buf->pool = wl_resource_get_user_data(pool);
-       buf->mem  = buf->pool->mem + offset;
+       sys_bdata_t *bdata = new0(sys_bdata_t);
+       bdata->pool = wl_resource_get_user_data(pool);
+       bdata->mem  = bdata->pool->mem + offset;
 
        printf("pool_create_buffer - %dx%d %p+%d : %d,%d,%d\n",
-                       width, height, buf->pool->mem, offset, id, stride, format);
+                       width, height, bdata->pool->mem, offset, id, stride, format);
 
-       if (offset > buf->pool->size || offset < 0)
+       if (offset > bdata->pool->size || offset < 0)
        {
                printf("\n\nerror\n\n");
                wl_resource_post_error(pool, WL_SHM_ERROR_INVALID_STRIDE,
@@ -188,11 +245,11 @@ static void pool_create_buffer(struct wl_client *cli, struct wl_resource *pool,
                format == WL_SHM_FORMAT_ARGB8888 ? CAIRO_FORMAT_ARGB32 :
                format == WL_SHM_FORMAT_XRGB8888 ? CAIRO_FORMAT_RGB24  : CAIRO_FORMAT_INVALID;
 
-       buf->surface = cairo_image_surface_create_for_data(buf->mem, cf, width, height, stride);
+       bdata->surface = cairo_image_surface_create_for_data(bdata->mem, cf, width, height, stride);
 
        struct wl_resource *res = wl_resource_create(cli, &wl_buffer_interface,
                                         wl_resource_get_version(pool), id);
-       wl_resource_set_implementation(res, &buffer_iface, buf, NULL);
+       wl_resource_set_implementation(res, &buffer_iface, bdata, NULL);
 }
 
 static void pool_destroy(struct wl_client *cli, struct wl_resource *pool)
@@ -215,7 +272,6 @@ static void pool_resize(struct wl_client *cli, struct wl_resource *pool,
        }
        data->mem  = ptr;
        data->size = size;
-       gdata[gidx++] = data;
 }
 
 static struct wl_shm_pool_interface pool_iface = {
@@ -238,7 +294,6 @@ static void shm_create_pool(struct wl_client *cli, struct wl_resource *shm,
 
        data->mem  = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
        data->size = size;
-       gdata[gidx++] = data;
 }
 
 static struct wl_shm_interface shm_iface = {
@@ -250,41 +305,115 @@ static struct wl_shm_interface shm_iface = {
  **************************/
 
 /* Pointer */
+static void pointer_kill(struct wl_resource *ptr)
+{
+       sys_cdata_t *cdata = wl_resource_get_user_data(ptr);
+       list_t *link = list_find(cdata->ptrs, ptr);
+       cdata->ptrs = list_remove(cdata->ptrs, link, 0);
+       if (!cdata->ptrs && !cdata->kbds && !cdata->tchs) {
+               list_t *clink = list_find(clients, cdata);
+               clients = list_remove(clients, clink, 1);
+       }
+}
+
+static void pointer_set_cursor(struct wl_client *cli, struct wl_resource *ptr,
+                          uint32_t serial, struct wl_resource *sfc,
+                          int32_t hotspot_x, int32_t hotspot_y)
+{
+       printf("pointer_set_cursor %d,%d\n", hotspot_x, hotspot_y);
+       win_t *win = wl_resource_get_user_data(sfc);
+       win->type = TYPE_CURSOR;
+       cursor_dx = hotspot_x;
+       cursor_dy = hotspot_y;
+       cursor    = win;
+}
+
+static void pointer_release(struct wl_client *cli, struct wl_resource *ptr)
+{
+       printf("pointer_release\n");
+}
+
 static struct wl_pointer_interface pointer_iface = {
-        .set_cursor = NULL,
-        .release    = NULL,
+        .set_cursor = pointer_set_cursor,
+        .release    = pointer_release,
 };
 
 /* Keyboard */
+static void keyboard_kill(struct wl_resource *kbd)
+{
+       sys_cdata_t *cdata = wl_resource_get_user_data(kbd);
+       list_t *link = list_find(cdata->kbds, kbd);
+       cdata->kbds = list_remove(cdata->kbds, link, 0);
+       if (!cdata->ptrs && !cdata->kbds && !cdata->tchs) {
+               list_t *clink = list_find(clients, cdata);
+               clients = list_remove(clients, clink, 1);
+       }
+}
+
+static void keyboard_release(struct wl_client *cli, struct wl_resource *kbd)
+{
+       printf("keyboard_release\n");
+}
+
 static struct wl_keyboard_interface keyboard_iface = {
-        .release    = NULL,
+        .release = keyboard_release,
 };
 
 /* Touch */
+static void touch_kill(struct wl_resource *tch)
+{
+       sys_cdata_t *cdata = wl_resource_get_user_data(tch);
+       list_t *link = list_find(cdata->tchs, tch);
+       cdata->tchs = list_remove(cdata->tchs, link, 0);
+       if (!cdata->ptrs && !cdata->kbds && !cdata->tchs) {
+               list_t *clink = list_find(clients, cdata);
+               clients = list_remove(clients, clink, 1);
+       }
+}
+
+static void touch_release(struct wl_client *cli, struct wl_resource *tch)
+{
+       printf("touch_release\n");
+}
+
 static struct wl_touch_interface touch_iface = {
-        .release    = NULL,
+        .release = touch_release,
 };
 
 /* Seat */
 static void seat_get_pointer(struct wl_client *cli, struct wl_resource *seat,
                uint32_t id) {
-       printf("seat_get_pointer\n");
+       sys_cdata_t *cdata = find_cdata(cli);
        struct wl_resource *res = wl_resource_create(cli, &wl_pointer_interface, 3, id);
-       wl_resource_set_implementation(res, &pointer_iface, NULL, NULL);
+       wl_resource_set_implementation(res, &pointer_iface, cdata, pointer_kill);
+       cdata->ptrs = list_insert(cdata->ptrs, res);
+       printf("seat_get_pointer - cli=%p cdata=%p ptr=%p\n", cli, cdata, res);
 }
 
 static void seat_get_keyboard(struct wl_client *cli, struct wl_resource *seat,
                uint32_t id) {
-       printf("seat_get_keyboard\n");
-       struct wl_resource *res = wl_resource_create(cli, &wl_keyboard_interface, 3, id);
-       wl_resource_set_implementation(res, &keyboard_iface, NULL, NULL);
+       sys_cdata_t *cdata = find_cdata(cli);
+       struct wl_resource *res = wl_resource_create(cli, &wl_keyboard_interface, 4, id);
+       wl_resource_set_implementation(res, &keyboard_iface, cdata, keyboard_kill);
+
+       //map = xkb_keymap_new_from_names(xkb->context, NULL, 0);
+       //xkb->context    = xkb_context_new(0);
+       //xkb->keymap.map = xkb_keymap_new_from_names(xkb->context, NULL, 0);
+       //wl_keyboard_send_keymap(cli, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+       //              keyboard->xkb.keymap.fd,
+       //              keyboard->xkb.keymap.size - 1);
+
+       cdata->kbds = list_insert(cdata->kbds, res);
+       printf("seat_get_keyboard - cli=%p cdata=%p kbd=%p\n", cli, cdata, res);
 }
 
 static void seat_get_touch(struct wl_client *cli, struct wl_resource *seat,
                uint32_t id) {
-       printf("seat_get_touch\n");
+       sys_cdata_t *cdata = find_cdata(cli);
        struct wl_resource *res = wl_resource_create(cli, &wl_touch_interface, 3, id);
-       wl_resource_set_implementation(res, &touch_iface, NULL, NULL);
+       wl_resource_set_implementation(res, &touch_iface, cdata, touch_kill);
+       cdata->tchs = list_insert(cdata->tchs, res);
+       printf("seat_get_touch - cli=%p cdata=%p tch=%p\n", cli, cdata, res);
 }
 
 static struct wl_seat_interface seat_iface = {
@@ -298,22 +427,64 @@ static struct wl_seat_interface seat_iface = {
  *****************************************/
 
 /* Data Offer */
+static void doff_accept(struct wl_client *cli, struct wl_resource *doff,
+              uint32_t serial, const char *mime_type)
+{
+       printf("doff_accept\n");
+}
+
+static void doff_receive(struct wl_client *cli, struct wl_resource *doff,
+               const char *mime_type, int32_t fd)
+{
+       printf("doff_receive\n");
+}
+
+static void doff_destroy(struct wl_client *cli, struct wl_resource *doff)
+{
+       printf("doff_destroy\n");
+}
+
 static struct wl_data_offer_interface doff_iface = {
-        .accept        = NULL,
-        .receive       = NULL,
-        .destroy       = NULL,
+        .accept  = doff_accept,
+        .receive = doff_receive,
+        .destroy = doff_destroy,
 };
 
 /* Data Source */
+static void dsrc_offer(struct wl_client *cli, struct wl_resource *dsrc,
+             const char *mime_type)
+{
+       (void)doff_iface;
+       printf("dsrc_offer\n");
+}
+
+static void dsrc_destroy(struct wl_client *cli, struct wl_resource *dsrc)
+{
+       printf("dsrc_destroy\n");
+}
+
 static struct wl_data_source_interface dsrc_iface = {
-        .offer         = NULL,
-        .destroy       = NULL,
+        .offer   = dsrc_offer,
+        .destroy = dsrc_destroy,
 };
 
 /* Data Device */
+static void ddev_start_drag(struct wl_client *cli, struct wl_resource *dsrc,
+                  struct wl_resource *source, struct wl_resource *origin,
+                  struct wl_resource *icon, uint32_t serial)
+{
+       printf("start_drag\n");
+}
+
+static void ddev_set_selection(struct wl_client *cli, struct wl_resource *dsrc,
+                     struct wl_resource *source, uint32_t serial)
+{
+       printf("set_selection\n");
+}
+
 static struct wl_data_device_interface ddev_iface = {
-        .start_drag    = NULL,
-        .set_selection = NULL,
+        .start_drag    = ddev_start_drag,
+        .set_selection = ddev_set_selection,
 };
 
 /* Data Device Manager */
@@ -342,66 +513,79 @@ static struct wl_data_device_manager_interface ddm_iface = {
  * Wayland Shell/Compositor Interface *
  **************************************/
 
-/* Callback */
-static void frame_callback(struct wl_resource *res)
+/* Surface */
+static void surface_kill(struct wl_resource *sfc)
 {
-       printf("frame_callback\n");
+       win_t  *win  = wl_resource_get_user_data(sfc);
+       list_t *link = list_find(windows, win);
+       printf("surface_kill - %p\n", win);
+       if (win == NULL)   return;
+       if (win == hover)  hover  = NULL;
+       if (win == focus)  focus  = NULL;
+       if (win == cursor) cursor = NULL;
+       free(win->sys);
+       free(win);
+       windows = list_remove(windows, link, 0);
+       wl_resource_set_user_data(sfc, NULL);
+       gtk_widget_queue_draw(screen);
 }
 
-/* Surface */
-static void surface_destroy(struct wl_client *cli, struct wl_resource *res)
+static void surface_destroy(struct wl_client *cli, struct wl_resource *sfc)
 {
        printf("surface_destroy\n");
+       surface_kill(sfc);
 }
 
-static void surface_attach(struct wl_client *cli, struct wl_resource *res,
+static void surface_attach(struct wl_client *cli, struct wl_resource *sfc,
                struct wl_resource *buf, int32_t x, int32_t y)
 {
-       sys_buf_t *data = wl_resource_get_user_data(buf);
-       printf("surface_attach - %p\n", data->pool->mem);
-       buffer = data;
+       win_t *win = wl_resource_get_user_data(sfc);
+       printf("surface_attach - %p - %d,%d\n", buf, x, y);
+       win->sys->buf = buf;
+       win->sys->x   = x;
+       win->sys->y   = y;
 }
 
-static void surface_damage(struct wl_client *cli, struct wl_resource *res,
+static void surface_damage(struct wl_client *cli, struct wl_resource *sfc,
                    int32_t x, int32_t y, int32_t width, int32_t height)
 {
        printf("surface_damage\n");
 }
 
-static void surface_frame(struct wl_client *cli, struct wl_resource *res,
+static void surface_frame(struct wl_client *cli, struct wl_resource *sfc,
                uint32_t id)
 {
        printf("surface_frame\n");
        struct wl_resource *cb = wl_resource_create(cli, &wl_callback_interface, 1, id);
-       wl_resource_set_implementation(cb, NULL, NULL, &frame_callback);
-        wl_callback_send_done(cb, time(NULL));
+       wl_resource_set_implementation(cb, NULL, NULL, NULL);
+        wl_callback_send_done(cb, get_time());
 }
 
-static void surface_set_opaque_region(struct wl_client *cli, struct wl_resource *res,
+static void surface_set_opaque_region(struct wl_client *cli, struct wl_resource *sfc,
                struct wl_resource *reg)
 {
        printf("surface_set_opaque_region\n");
 }
 
-static void surface_set_input_region(struct wl_client *cli, struct wl_resource *res,
+static void surface_set_input_region(struct wl_client *cli, struct wl_resource *sfc,
                struct wl_resource *reg)
 {
        printf("surface_set_input_region\n");
 }
 
-static void surface_commit(struct wl_client *cli, struct wl_resource *res)
+static void surface_commit(struct wl_client *cli, struct wl_resource *sfc)
 {
        printf("surface_commit\n");
-       gtk_widget_queue_draw(window);
+       gtk_widget_queue_draw(screen);
 }
 
-static void surface_set_buffer_transform(struct wl_client *cli, struct wl_resource *res,
+static void surface_set_buffer_transform(struct wl_client *cli, struct wl_resource *sfc,
                int32_t transform)
 {
        printf("surface_set_buffer_transform\n");
 }
 
-static void surface_set_buffer_scale(struct wl_client *cli, struct wl_resource *res,
+static void surface_set_buffer_scale(struct wl_client *cli, struct wl_resource *sfc,
                int32_t scale)
 {
        printf("surface_set_buffer_scale\n");
@@ -420,18 +604,18 @@ static struct wl_surface_interface surface_iface = {
 };
 
 /* Region */
-static void region_destroy(struct wl_client *cli, struct wl_resource *res)
+static void region_destroy(struct wl_client *cli, struct wl_resource *reg)
 {
        printf("region_destroy\n");
 }
 
-static void region_add(struct wl_client *cli, struct wl_resource *res,
+static void region_add(struct wl_client *cli, struct wl_resource *reg,
                 int32_t x, int32_t y, int32_t width, int32_t height)
 {
        printf("region_add\n");
 }
 
-static void region_subtract(struct wl_client *cli, struct wl_resource *res,
+static void region_subtract(struct wl_client *cli, struct wl_resource *reg,
                      int32_t x, int32_t y, int32_t width, int32_t height)
 {
        printf("region_subtract\n");
@@ -447,10 +631,20 @@ static struct wl_region_interface region_iface = {
 static void comp_create_surface(struct wl_client *cli, struct wl_resource *comp,
                uint32_t id)
 {
-       printf("comp_create_surface\n");
+       win_t *win = new0(win_t);
+       win->sys   = new0(win_sys_t);
+
        struct wl_resource *res = wl_resource_create(cli, &wl_surface_interface, 3, id);
-       wl_resource_set_implementation(res, &surface_iface, NULL, NULL);
+       wl_resource_set_implementation(res, &surface_iface, win, surface_kill);
        wl_surface_send_enter(res, output);
+
+       win->sys->sfc   = res;
+       win->sys->cdata = find_cdata(cli);
+
+       windows = list_insert(windows, win);
+
+       printf("comp_create_surface - cli=%p win=%p cdata=%p\n",
+                       cli, win, win->sys->cdata);
 }
 
 static void comp_create_region(struct wl_client *cli, struct wl_resource *comp,
@@ -467,61 +661,70 @@ static struct wl_compositor_interface comp_iface = {
 };
 
 /* Shell Surface */
-static void ssurface_pong(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_kill(struct wl_resource *ssfc)
+{
+       win_t *win = wl_resource_get_user_data(ssfc);
+       printf("ssurface_kill - %p\n", win);
+       win->sys->ssfc = NULL;
+       if (!win->sys->xsfc)
+               wm_remove(win);
+}
+
+static void ssurface_pong(struct wl_client *cli, struct wl_resource *ssfc,
                uint32_t serial)
 {
        printf("ssurface_pong\n");
 }
 
-static void ssurface_move(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_move(struct wl_client *cli, struct wl_resource *ssfc,
                struct wl_resource *seat, uint32_t serial)
 {
        printf("ssurface_move\n");
 }
 
-static void ssurface_resize(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_resize(struct wl_client *cli, struct wl_resource *ssfc,
                struct wl_resource *seat, uint32_t serial, uint32_t edges)
 {
        printf("ssurface_resize\n");
 }
 
-static void ssurface_set_toplevel(struct wl_client *cli, struct wl_resource *res)
+static void ssurface_set_toplevel(struct wl_client *cli, struct wl_resource *ssfc)
 {
        printf("ssurface_set_toplevel\n");
 }
 
-static void ssurface_set_transient(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_set_transient(struct wl_client *cli, struct wl_resource *ssfc,
                struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags)
 {
        printf("ssurface_set_transient\n");
 }
 
-static void ssurface_set_fullscreen(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_set_fullscreen(struct wl_client *cli, struct wl_resource *ssfc,
                uint32_t method, uint32_t framerate, struct wl_resource *out)
 {
        printf("ssurface_set_fullscreen\n");
 }
 
-static void ssurface_set_popup(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_set_popup(struct wl_client *cli, struct wl_resource *ssfc,
                struct wl_resource *seat, uint32_t serial, struct wl_resource *parent,
                int32_t x, int32_t y, uint32_t flags)
 {
        printf("ssurface_set_popup\n");
 }
 
-static void ssurface_set_maximized(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_set_maximized(struct wl_client *cli, struct wl_resource *ssfc,
                struct wl_resource *out)
 {
        printf("ssurface_set_maximized\n");
 }
 
-static void ssurface_set_title(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_set_title(struct wl_client *cli, struct wl_resource *ssfc,
                const char *title)
 {
        printf("ssurface_set_title\n");
 }
 
-static void ssurface_set_class(struct wl_client *cli, struct wl_resource *res,
+static void ssurface_set_class(struct wl_client *cli, struct wl_resource *ssfc,
                const char *class)
 {
        printf("ssurface_set_class\n");
@@ -543,15 +746,224 @@ static struct wl_shell_surface_interface ssurface_iface = {
 /* Shell */
 static void shell_get_shell_surface(struct wl_client *cli, struct wl_resource *shell, uint32_t id,
                               struct wl_resource *sfc) {
-       printf("shell_get_shell_surface\n");
+       win_t *win = wl_resource_get_user_data(sfc);
+       printf("shell_get_shell_surface - %p\n", win);
+
        struct wl_resource *res = wl_resource_create(cli, &wl_shell_surface_interface, 1, id);
-       wl_resource_set_implementation(res, &ssurface_iface, NULL, NULL);
+       wl_resource_set_implementation(res, &ssurface_iface, win, ssurface_kill);
+
+       win->type = TYPE_NORMAL;
+       win->sys->ssfc = res;
+       wm_insert(win);
 }
 
 static struct wl_shell_interface shell_iface = {
        .get_shell_surface = shell_get_shell_surface,
 };
 
+/* XDG Popup */
+static void xpopup_destroy(struct wl_client *cli, struct wl_resource *xpopup)
+{
+       printf("xpopup_destroy\n");
+}
+
+static struct xdg_popup_interface xpopup_iface = {
+       .destroy = xpopup_destroy,
+};
+
+/* XDG Surface */
+static void xsurface_kill(struct wl_resource *xsfc)
+{
+       win_t *win = wl_resource_get_user_data(xsfc);
+       printf("xsurface_kill - %p\n", win);
+       if (!win)
+               return;
+       win->sys->xsfc = NULL;
+       if (!win->sys->ssfc)
+               wm_remove(win);
+}
+
+static void xsurface_destroy(struct wl_client *cli, struct wl_resource *xsfc)
+{
+       printf("xsurface_destroy\n");
+       xsurface_kill(xsfc);
+}
+
+static void xsurface_set_parent(struct wl_client *cli, struct wl_resource *xsfc,
+               struct wl_resource *parent)
+{
+       win_t *win = wl_resource_get_user_data(xsfc);
+       printf("xsurface_set_parent - %p\n", win);
+       //win->type = TYPE_DIALOG;
+}
+
+static void xsurface_set_title(struct wl_client *cli, struct wl_resource *xsfc,
+               const char *title)
+{
+       printf("xsurface_set_title\n");
+}
+
+static void xsurface_set_app_id(struct wl_client *cli, struct wl_resource *xsfc,
+               const char *app_id)
+{
+       printf("xsurface_set_app_id\n");
+}
+
+static void xsurface_show_window_menu(struct wl_client *cli, struct wl_resource *xsfc,
+               struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y)
+{
+       printf("xsurface_show_window_menu\n");
+}
+
+static void xsurface_move(struct wl_client *cli, struct wl_resource *xsfc,
+               struct wl_resource *seat, uint32_t serial)
+{
+       printf("xsurface_move\n");
+}
+
+static void xsurface_resize(struct wl_client *cli, struct wl_resource *xsfc,
+               struct wl_resource *seat, uint32_t serial, uint32_t edges)
+{
+       printf("xsurface_resize\n");
+}
+
+static void xsurface_ack_configure(struct wl_client *cli, struct wl_resource *xsfc,
+               uint32_t serial)
+{
+       printf("xsurface_ack_configure\n");
+}
+
+static void xsurface_set_window_geometry(struct wl_client *cli, struct wl_resource *xsfc,
+               int32_t x, int32_t y, int32_t width, int32_t height)
+{
+       win_t *win = wl_resource_get_user_data(xsfc);
+       printf("xsurface_set_window_geometry - %p\n", win);
+       win->sys->wx = x;
+       win->sys->wy = y;
+       win->sys->ww = width;
+       win->sys->wh = height;
+}
+
+static void xsurface_set_maximized(struct wl_client *cli, struct wl_resource *xsfc)
+{
+       printf("xsurface_set_maximized\n");
+}
+
+static void xsurface_unset_maximized(struct wl_client *cli, struct wl_resource *xsfc)
+{
+       printf("xsurface_unset_maximized\n");
+}
+
+static void xsurface_set_fullscreen(struct wl_client *cli, struct wl_resource *xsfc,
+               struct wl_resource *output)
+{
+       printf("xsurface_set_fullscreen\n");
+}
+
+static void xsurface_unset_fullscreen(struct wl_client *cli, struct wl_resource *xsfc)
+{
+       printf("xsurface_unset_fullscreen\n");
+}
+
+static void xsurface_set_minimized(struct wl_client *cli, struct wl_resource *xsfc)
+{
+       printf("xsurface_set_minimized\n");
+}
+
+static struct xdg_surface_interface xsurface_iface = {
+       .destroy             = xsurface_destroy,
+       .set_parent          = xsurface_set_parent,
+       .set_title           = xsurface_set_title,
+       .set_app_id          = xsurface_set_app_id,
+       .show_window_menu    = xsurface_show_window_menu,
+       .move                = xsurface_move,
+       .resize              = xsurface_resize,
+       .ack_configure       = xsurface_ack_configure,
+       .set_window_geometry = xsurface_set_window_geometry,
+       .set_maximized       = xsurface_set_maximized,
+       .unset_maximized     = xsurface_unset_maximized,
+       .set_fullscreen      = xsurface_set_fullscreen,
+       .unset_fullscreen    = xsurface_unset_fullscreen,
+       .set_minimized       = xsurface_set_minimized,
+};
+
+/* XDG Shell */
+static void xshell_use_unstable_version(struct wl_client *cli, struct wl_resource *xshell,
+               int32_t version)
+{
+       printf("xshell_use_unstable_version\n");
+}
+
+static void xshell_get_xdg_surface(struct wl_client *cli, struct wl_resource *xshell,
+               uint32_t id, struct wl_resource *sfc)
+{
+       win_t *win = wl_resource_get_user_data(sfc);
+       printf("xshell_get_xdg_surface - %p\n", win);
+
+       struct wl_resource *res = wl_resource_create(cli, &xdg_surface_interface, 1, id);
+       wl_resource_set_implementation(res, &xsurface_iface, win, xsurface_kill);
+
+       win->type = TYPE_NORMAL;
+       win->sys->xsfc = res;
+       wm_insert(win);
+}
+
+static void xshell_get_xdg_popup(struct wl_client *cli, struct wl_resource *xshell,
+               uint32_t id, struct wl_resource *sfc, struct wl_resource *parent,
+               struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y, uint32_t flags)
+{
+       win_t *win = wl_resource_get_user_data(sfc);
+       printf("xshell_get_xdg_popup - %p @ %d,%d\n", win, x, y);
+
+       struct wl_resource *res = wl_resource_create(cli, &xdg_popup_interface, 1, id);
+       wl_resource_set_implementation(res, &xpopup_iface, win, NULL);
+
+       win_t *par  = wl_resource_get_user_data(parent);
+       win->type   = TYPE_POPUP;
+       win->parent = par;
+       win->x      = x;
+       win->y      = y;
+}
+
+static void xshell_pong(struct wl_client *cli, struct wl_resource *xshell,
+               uint32_t serial)
+{
+       printf("xshell_pong\n");
+}
+
+static struct xdg_shell_interface xshell_iface = {
+       .use_unstable_version = xshell_use_unstable_version,
+       .get_xdg_surface      = xshell_get_xdg_surface,
+       .get_xdg_popup        = xshell_get_xdg_popup,
+       .pong                 = xshell_pong,
+};
+
+/* GTK Surface */
+static void gsurface_set_dbus_properties(struct wl_client *cli, struct wl_resource *gsfc,
+                           const char *application_id, const char *app_menu_path,
+                           const char *menubar_path, const char *window_object_path,
+                           const char *application_object_path, const char *unique_bus_name)
+{
+       printf("gsurface_set_dbus_properties\n");
+}
+
+static struct gtk_surface_interface gsurface_iface = {
+       .set_dbus_properties = gsurface_set_dbus_properties,
+};
+
+/* GTK Shell */
+static void gshell_get_gtk_surface(struct wl_client *cli, struct wl_resource *gshell,
+               uint32_t id, struct wl_resource *sfc)
+{
+       printf("gshell_get_gtk_surface\n");
+       struct wl_resource *res = wl_resource_create(cli, &gtk_surface_interface, 1, id);
+       wl_resource_set_implementation(res, &gsurface_iface, NULL, NULL);
+}
+
+static struct gtk_shell_interface gshell_iface = {
+       .get_gtk_surface = gshell_get_gtk_surface,
+};
+
 /*******************
  * Wayland Globals *
  *******************/
@@ -563,6 +975,8 @@ static struct wl_global *ref_seat;
 static struct wl_global *ref_ddm;
 static struct wl_global *ref_comp;
 static struct wl_global *ref_shell;
+static struct wl_global *ref_xshell;
+static struct wl_global *ref_gshell;
 
 /* Bind functions */
 static void bind_shm(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
@@ -591,10 +1005,10 @@ static void bind_output(struct wl_client *cli, void *data, uint32_t version, uin
                        WL_OUTPUT_SUBPIXEL_UNKNOWN,  // subpixel format
                        "unknown", "unknown",        // make, model
                        WL_OUTPUT_TRANSFORM_NORMAL); // rotatoin
-       //wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 800,  600,  60);
-       //wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 1024, 768,  60);
+       wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 800,  600,  60);
+       wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 1024, 768,  60);
        wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 1280, 1024, 60);
-       //wl_output_send_done(res);
+       wl_output_send_done(res);
 }
 
 static void bind_seat(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
@@ -631,13 +1045,209 @@ static void bind_shell(struct wl_client *cli, void *data, uint32_t version, uint
        wl_resource_set_implementation(res, &shell_iface, NULL, NULL);
 }
 
+static void bind_xshell(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
+{
+       printf("bind_xshell\n");
+       struct wl_resource *res = wl_resource_create(cli, &xdg_shell_interface, version, id);
+       wl_resource_set_implementation(res, &xshell_iface, NULL, NULL);
+}
+
+static void bind_gshell(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
+{
+       printf("bind_gshell\n");
+       struct wl_resource *res = wl_resource_create(cli, &gtk_shell_interface, version, id);
+       wl_resource_set_implementation(res, &gshell_iface, NULL, NULL);
+}
+
+/*****************
+ * Gtk Callbacks *
+ *****************/
+
+static void on_destroy(GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+       printf("on_destroy\n");
+       sys_exit();
+}
+
+static gboolean on_key(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+{
+       /* Handle special keys */
+       if (event->state  &  GDK_CONTROL_MASK &&
+           event->type   == GDK_KEY_PRESS    &&
+           event->keyval == GDK_KEY_Return)
+               g_spawn_command_line_async("vte2_90", NULL);
+
+       /* Send key to WM */
+       if (focus) {
+               event_t ev  = tolower(event->keyval);
+               mod_t   mod = get_mod(event->state, event->type == GDK_KEY_RELEASE);
+               ptr_t   ptr = get_ptr(focus);
+               if (wm_handle_event(focus, ev, mod, ptr))
+                       return TRUE;
+       }
+
+       /* Skip if no focused window */
+       if (!focus || !focus->sys->cdata)
+               return FALSE;
+
+       /* Send key to wayland */
+       printf(g_ascii_isprint(event->keyval)
+               ? "on_key - win=%p cdata=%p '%c'\n"
+               : "on_key - win=%p cdata=%p 0x%X\n",
+               focus, focus?focus->sys->cdata:0, event->keyval);
+       for (list_t *cur = focus->sys->cdata->kbds; cur; cur = cur->next) {
+               uint32_t serial = get_serial();
+               uint32_t stamp  = get_time();
+               uint32_t key    = event->hardware_keycode-8;
+               uint32_t state  = event->type == GDK_KEY_PRESS
+                       ? WL_KEYBOARD_KEY_STATE_PRESSED
+                       : WL_KEYBOARD_KEY_STATE_RELEASED;
+               wl_keyboard_send_key(cur->data, serial, stamp, key, state);
+               printf("    send -> %p tm=%d key=%d state=%d\n",
+                               cur->data, stamp, key, state);
+       }
+       return TRUE;
+}
+
+static gboolean on_button(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+       win_t *win = find_win(event->x, event->y);
+       printf("on_button - win=%p cdata=%p\n",
+                       win, win?win->sys->cdata:0);
+       if (!win || !win->sys->cdata)
+               return FALSE;
+       for (list_t *cur = win->sys->cdata->ptrs; cur; cur = cur->next) {
+               uint32_t serial = get_serial();
+               uint32_t stamp  = get_time();
+               uint32_t button = BTN_MOUSE+(event->button-1);
+               uint32_t state  = event->type == GDK_BUTTON_PRESS
+                       ? WL_POINTER_BUTTON_STATE_PRESSED
+                       : WL_POINTER_BUTTON_STATE_RELEASED;
+               wl_pointer_send_button(cur->data, serial, stamp, button, state);
+               printf("    send -> %p tm=%d btn=%d state=%d\n",
+                               cur->data, stamp, button, state);
+       }
+       return TRUE;
+}
+
+static gboolean on_move(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
+{
+       win_t *win = find_win(event->x, event->y);
+       if (!win)
+               return FALSE;
+
+       /* Queue draw event for cursor */
+       gtk_widget_queue_draw(screen);
+
+       /* Save cursor position */
+       cursor_x = event->x;
+       cursor_y = event->y;
+
+       /* Send enter/leave */
+       if (win != hover) {
+               wm_handle_event(hover, EV_LEAVE, MOD(), PTR());
+               wm_handle_event(win,   EV_ENTER, MOD(), PTR());
+               hover = win;
+       }
+
+       /* Sent pointer to WM */
+       if (wm_handle_ptr(win, get_ptr(win)))
+               return TRUE;
+
+       /* Send motion event to window */
+       uint32_t   t = get_time();
+       wl_fixed_t x = wl_fixed_from_double(cursor_x - win->x);
+       wl_fixed_t y = wl_fixed_from_double(cursor_y - win->y);
+       for (list_t *cur = win->sys->cdata->ptrs; cur; cur = cur->next)
+               wl_pointer_send_motion(cur->data, t, x, y);
+       return TRUE;
+}
+
+static void on_size(GtkWidget *widget, GtkAllocation *alloc, gpointer user_data)
+{
+       printf("on_size - %dx%d\n", alloc->width, alloc->height);
+       root->w = alloc->width;
+       root->h = alloc->height;
+}
+
+static gboolean on_draw(GtkWidget *widget, cairo_t *cairo, gpointer user_data)
+{
+       printf("on_draw\n");
+
+       //wm_update(); // Hacks for now
+
+       /* Draw windows bottom up */
+       list_t *bottom = list_last(windows);
+       for (list_t *cur = bottom; cur; cur = cur->prev) {
+               win_t       *win   = cur->data;
+               if (win->sys->buf == NULL)
+                       continue;
+               if (win->type == TYPE_CURSOR)
+                       continue;
+               sys_bdata_t *bdata = wl_resource_get_user_data(win->sys->buf);
+               int x = win->x;
+               int y = win->y;
+               if (win->type == TYPE_POPUP && win->parent) {
+                       x += win->parent->x;
+                       y += win->parent->y;
+               }
+               //if (win->sys->wx) x -= win->sys->wx;
+               //if (win->sys->wy) y -= win->sys->wy;
+               printf("    win = %p %dx%d @ %d,%d\n",
+                               win, win->w, win->h, x, y);
+               cairo_surface_mark_dirty(bdata->surface);
+               cairo_set_source_surface(cairo, bdata->surface, x, y);
+               cairo_paint(cairo);
+               //wl_buffer_send_release(win->sys->buf);
+               //win->sys->buf = 0;
+       }
+
+       /* Draw cursor */
+       if (cursor && cursor->sys->buf) {
+               int x = cursor_x, y = cursor_y;
+               sys_bdata_t *bdata = wl_resource_get_user_data(cursor->sys->buf);
+               cairo_surface_mark_dirty(bdata->surface);
+               cairo_set_source_surface(cairo, bdata->surface, x, y);
+               cairo_paint(cairo);
+       }
+
+       return TRUE;
+}
+
+static gboolean on_wayland(gpointer user_data)
+{
+       // TODO - convert to polled execution
+       wl_display_flush_clients(display);
+       wl_event_loop_dispatch(events, 0);
+       return TRUE;
+}
+
 /********************
  * System functions *
  ********************/
 void sys_move(win_t *win, int x, int y, int w, int h)
 {
+       if (win->x == x && win->y == y &&
+           win->w == w && win->h == h)
+               return;
        printf("sys_move: %p - %d,%d  %dx%d\n",
                        win, x, y, w, h);
+
+       win->x = x;
+       win->y = y;
+       win->w = w;
+       win->h = h;
+
+       if (win->sys->ssfc)
+               wl_shell_surface_send_configure(win->sys->ssfc,
+                               WL_SHELL_SURFACE_RESIZE_NONE, w, h);
+
+       if (win->sys->xsfc)
+               xdg_surface_send_configure(win->sys->xsfc, w, h,
+                               (win == focus) ? &xstate_active : &xstate_normal,
+                               get_serial());
+
+       gtk_widget_queue_draw(screen);
 }
 
 void sys_raise(win_t *win)
@@ -647,7 +1257,37 @@ void sys_raise(win_t *win)
 
 void sys_focus(win_t *win)
 {
+       if (win == focus)
+               return;
        printf("sys_focus: %p\n", win);
+
+       /* Send leave event */
+       uint32_t   s = get_serial();
+       wl_fixed_t x = wl_fixed_from_double(cursor_x - win->x);
+       wl_fixed_t y = wl_fixed_from_double(cursor_y - win->y);
+       if  (focus && focus->sys->sfc && focus->sys->cdata) {
+               printf("sys_focus - leave win=%p\n", focus);
+               for (list_t *cur = focus->sys->cdata->ptrs; cur; cur = cur->next)
+                       wl_pointer_send_leave(cur->data, s, focus->sys->sfc);
+               for (list_t *cur = focus->sys->cdata->kbds; cur; cur = cur->next)
+                       wl_keyboard_send_leave(cur->data, s, focus->sys->sfc);
+               if (focus->sys->xsfc)
+                       xdg_surface_send_configure(focus->sys->xsfc, focus->w, focus->h,
+                                       &xstate_normal, get_serial());
+       }
+       if  (win && win->sys->sfc && win->sys->cdata) {
+               printf("sys_focus - enter win=%p\n", win);
+               for (list_t *cur = win->sys->cdata->ptrs; cur; cur = cur->next)
+                       wl_pointer_send_enter(cur->data, s, win->sys->sfc, x, y);
+               for (list_t *cur = win->sys->cdata->kbds; cur; cur = cur->next)
+                       wl_keyboard_send_enter(cur->data, s, win->sys->sfc, &keys);
+               if (win->sys->xsfc)
+                       xdg_surface_send_configure(win->sys->xsfc, win->w, win->h,
+                                       &xstate_active, get_serial());
+       }
+
+       /* Update focused window */
+       focus = win;
 }
 
 void sys_show(win_t *win, state_t state)
@@ -677,6 +1317,27 @@ win_t *sys_init(void)
 {
        printf("sys_init\n");
 
+       /* Create root window */
+       root = new0(win_t);
+       root->x = 0;
+       root->y = 0;
+       root->w = 800;
+       root->h = 600;
+
+       /* Initalize constants */
+       set_array(&xstate_normal, 0);
+       set_array(&xstate_active, 1,
+               XDG_SURFACE_STATE_ACTIVATED);
+       set_array(&xstate_max,2,
+               XDG_SURFACE_STATE_ACTIVATED,
+               XDG_SURFACE_STATE_MAXIMIZED);
+       set_array(&xstate_full, 2,
+               XDG_SURFACE_STATE_ACTIVATED,
+               XDG_SURFACE_STATE_FULLSCREEN);
+       set_array(&xstate_resize, 2,
+               XDG_SURFACE_STATE_ACTIVATED,
+               XDG_SURFACE_STATE_RESIZING);
+
        /* Register log handler */
        wl_log_set_handler_server((wl_log_func_t)vprintf);
 
@@ -694,25 +1355,33 @@ win_t *sys_init(void)
        ref_ddm    = wl_global_create(display, &wl_data_device_manager_interface, 1, NULL, &bind_ddm);
        ref_shell  = wl_global_create(display, &wl_shell_interface,               1, NULL, &bind_shell);
        ref_comp   = wl_global_create(display, &wl_compositor_interface,          3, NULL, &bind_comp);
-       ref_seat   = wl_global_create(display, &wl_seat_interface,                3, NULL, &bind_seat);
+       ref_seat   = wl_global_create(display, &wl_seat_interface,                4, NULL, &bind_seat);
+       ref_xshell = wl_global_create(display, &xdg_shell_interface,              1, NULL, &bind_xshell);
+       ref_gshell = wl_global_create(display, &gtk_shell_interface,              1, NULL, &bind_gshell);
 
        /* Setup GTK display */
        gtk_init(&conf_argc, &conf_argv);
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-       gtk_widget_add_events(window,
+       screen = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       gtk_widget_add_events(screen,
                        GDK_KEY_PRESS_MASK |
                        GDK_BUTTON_PRESS_MASK |
                        GDK_BUTTON_RELEASE_MASK |
                        GDK_POINTER_MOTION_MASK);
-       g_signal_connect(window, "destroy",             G_CALLBACK(on_destroy), NULL);
-       g_signal_connect(window, "key-press-event",     G_CALLBACK(on_key),     NULL);
-       g_signal_connect(window, "button-press-event",  G_CALLBACK(on_button),  NULL);
-       g_signal_connect(window, "motion-notify-event", G_CALLBACK(on_move),    NULL);
-       g_signal_connect(window, "draw",                G_CALLBACK(on_draw),    NULL);
+       g_signal_connect(screen, "destroy",              G_CALLBACK(on_destroy), NULL);
+       g_signal_connect(screen, "key-press-event",      G_CALLBACK(on_key),     NULL);
+       g_signal_connect(screen, "key-release-event",    G_CALLBACK(on_key),     NULL);
+       g_signal_connect(screen, "button-press-event",   G_CALLBACK(on_button),  NULL);
+       g_signal_connect(screen, "button-release-event", G_CALLBACK(on_button),  NULL);
+       g_signal_connect(screen, "motion-notify-event",  G_CALLBACK(on_move),    NULL);
+       g_signal_connect(screen, "size-allocate",        G_CALLBACK(on_size),    NULL);
+       g_signal_connect(screen, "draw",                 G_CALLBACK(on_draw),    NULL);
        g_timeout_add(1000/60, on_wayland, NULL);
-       gtk_widget_show(window);
+       gtk_widget_show(screen);
+
+       /* Setup environment */
+       setenv("GDK_BACKEND", "wayland", 1);
 
-       return new0(win_t);
+       return root;
 }
 
 void sys_run(win_t *root)