/*
- * 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,
};
/***********************************
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,
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)
}
data->mem = ptr;
data->size = size;
- gdata[gidx++] = data;
}
static struct wl_shm_pool_interface pool_iface = {
data->mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
data->size = size;
- gdata[gidx++] = data;
}
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 = {
*****************************************/
/* 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 */
* 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");
};
/* 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");
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,
};
/* 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");
/* 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, >k_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 *
*******************/
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)
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)
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, >k_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)
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)
{
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);
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, >k_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)