summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vincent.sanders@collabora.co.uk>2013-03-20 11:49:00 (GMT)
committer Vincent Sanders <vincent.sanders@collabora.co.uk>2013-04-09 16:27:41 (GMT)
commit08f5d6e00ff12502cea62e7410da3df0cc18ab3b (patch)
treedf0ab7a1f4c7a46a0743f186b022219be630b676
parentab47efdb2ee3e0199fbfc3fa42aa1ac77794cf94 (diff)
downloadlibnsfb-08f5d6e00ff12502cea62e7410da3df0cc18ab3b.tar.gz
libnsfb-08f5d6e00ff12502cea62e7410da3df0cc18ab3b.tar.bz2
Wayland surface handler with mouse input based on X surface handler
-rw-r--r--Makefile16
-rw-r--r--include/libnsfb.h3
-rw-r--r--src/surface/Makefile20
-rw-r--r--src/surface/vnc.c8
-rw-r--r--src/surface/wld.c2034
-rw-r--r--src/surface/x.c4
-rwxr-xr-xtest/runtest.sh2
7 files changed, 2071 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index 8358de6..89d7b6b 100644
--- a/Makefile
+++ b/Makefile
@@ -18,14 +18,21 @@ WARNFLAGS := -Wall -Wextra -Wundef -Wpointer-arith -Wcast-align \
-Wmissing-declarations -Wnested-externs -Werror -pedantic \
-Wno-overlength-strings # For nsglobe.c
CFLAGS := -g -std=c99 -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112L \
- -I$(CURDIR)/include/ -I$(CURDIR)/src $(WARNFLAGS) $(CFLAGS)
+ -I$(CURDIR)/include/ -I$(CURDIR)/src $(WARNFLAGS) $(CFLAGS) -Wno-error
NSFB_XCB_PKG_NAMES := xcb xcb-icccm xcb-image xcb-keysyms xcb-atom
+# determine which surface handlers can be compiled based upon avalable library
$(eval $(call pkg_config_package_available,NSFB_VNC_AVAILABLE,libvncserver))
$(eval $(call pkg_config_package_available,NSFB_SDL_AVAILABLE,sdl))
$(eval $(call pkg_config_package_available,NSFB_XCB_AVAILABLE,$(NSFB_XCB_PKG_NAMES)))
+$(eval $(call pkg_config_package_available,NSFB_WLD_AVAILABLE,wayland-client))
+# surfaces not detectable via pkg-config
+NSFB_ABLE_AVAILABLE := no
+NSFB_LINUX_AVAILABLE := yes
+
+# Flags and setup for each support library
ifeq ($(NSFB_SDL_AVAILABLE),yes)
$(eval $(call pkg_config_package_add_flags,sdl,CFLAGS))
$(eval $(call pkg_config_package_add_flags,sdl,TESTCFLAGS,TESTLDFLAGS))
@@ -78,6 +85,13 @@ ifeq ($(NSFB_VNC_AVAILABLE),yes)
REQUIRED_PKGS := $(REQUIRED_PKGS) libvncserver
endif
+ifeq ($(NSFB_WLD_AVAILABLE),yes)
+ $(eval $(call pkg_config_package_add_flags,wayland-client,CFLAGS))
+ $(eval $(call pkg_config_package_add_flags,wayland-client,TESTCFLAGS,TESTLDFLAGS))
+
+ REQUIRED_PKGS := $(REQUIRED_PKGS) wayland-client
+endif
+
TESTLDFLAGS := -lm -Wl,--whole-archive -l$(COMPONENT) -Wl,--no-whole-archive $(TESTLDFLAGS)
include $(NSBUILD)/Makefile.top
diff --git a/include/libnsfb.h b/include/libnsfb.h
index da8e5f6..75d6b50 100644
--- a/include/libnsfb.h
+++ b/include/libnsfb.h
@@ -40,7 +40,8 @@ enum nsfb_type_e {
NSFB_SURFACE_LINUX, /**< Linux framebuffer surface */
NSFB_SURFACE_VNC, /**< VNC surface */
NSFB_SURFACE_ABLE, /**< ABLE framebuffer surface */
- NSFB_SURFACE_X /**< X windows surface */
+ NSFB_SURFACE_X, /**< X windows surface */
+ NSFB_SURFACE_WL /**< Wayland surface */
};
enum nsfb_format_e {
diff --git a/src/surface/Makefile b/src/surface/Makefile
index 012d9cd..ad23cc4 100644
--- a/src/surface/Makefile
+++ b/src/surface/Makefile
@@ -1,16 +1,16 @@
# Sources
-DIR_SOURCES := surface.c able.c ram.c linux.c
-ifeq ($(NSFB_SDL_AVAILABLE),yes)
- DIR_SOURCES := $(DIR_SOURCES) sdl.c
-endif
+# Common surface code and heap based surface handler
+SURFACE_HANDLER_yes := surface.c ram.c
-ifeq ($(NSFB_XCB_AVAILABLE),yes)
- DIR_SOURCES := $(DIR_SOURCES) x.c
-endif
+# optional surface handlers
+SURFACE_HANDLER_$(NSFB_ABLE_AVAILABLE) += able.c
+SURFACE_HANDLER_$(NSFB_LINUX_AVAILABLE) += linux.c
+SURFACE_HANDLER_$(NSFB_SDL_AVAILABLE) += sdl.c
+SURFACE_HANDLER_$(NSFB_XCB_AVAILABLE) += x.c
+SURFACE_HANDLER_$(NSFB_VNC_AVAILABLE) += vnc.c
+SURFACE_HANDLER_$(NSFB_WLD_AVAILABLE) += wld.c
-ifeq ($(NSFB_VNC_AVAILABLE),yes)
- DIR_SOURCES := $(DIR_SOURCES) vnc.c
-endif
+DIR_SOURCES := $(SURFACE_HANDLER_yes)
include $(NSBUILD)/Makefile.subdir
diff --git a/src/surface/vnc.c b/src/surface/vnc.c
index eb32560..ca9455b 100644
--- a/src/surface/vnc.c
+++ b/src/surface/vnc.c
@@ -497,7 +497,13 @@ static bool vnc_input(nsfb_t *nsfb, nsfb_event_t *event, int timeout)
event->value.controlcode = NSFB_CONTROL_TIMEOUT;
ret = rfbProcessEvents(vncscreen, timeout * 1000);
- return true;
+ if (ret == 0) {
+ /* valid event */
+ return true;
+
+ }
+
+ /* connection error occurred */
}
return false;
diff --git a/src/surface/wld.c b/src/surface/wld.c
new file mode 100644
index 0000000..7843639
--- a/dev/null
+++ b/src/surface/wld.c
@@ -0,0 +1,2034 @@
+/*
+ * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#define _XOPEN_SOURCE 500
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <linux/input.h>
+#include <wayland-client.h>
+
+#include "libnsfb.h"
+#include "libnsfb_event.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "surface.h"
+#include "plot.h"
+#include "cursor.h"
+
+struct wld_event {
+ struct wld_event *next;
+
+ nsfb_event_t event;
+};
+
+/** structure for display, registry and other global objects that
+ * should be cached when connecting to a wayland instance
+ */
+struct wld_connection {
+ struct wl_display *display; /**< connection object */
+ struct wl_registry *registry; /**< registry object */
+
+ /** compositor object, available once teh registry messages have
+ * been processed
+ */
+ struct wl_compositor *compositor;
+
+ /** shell object, available once the registry messages have been
+ * processed
+ */
+ struct wl_shell *shell;
+
+ /** shared memory object, available once the registry messages
+ * have been processed
+ */
+ struct wl_shm *shm;
+
+ /** shared memory formats available */
+ uint32_t shm_formats;
+
+ /** list of input seats */
+ struct wl_list input_list;
+
+ /** event queue */
+ struct wld_event *event_head;
+ struct wld_event *event_tail;
+};
+
+/** wayland input seat */
+struct wld_input {
+ struct wl_list link; /**< input list */
+
+ struct wld_connection* connection; /**< connection to wayland server */
+
+ struct wl_seat *seat; /**< The seat object */
+
+ struct wl_pointer *pointer;
+ struct wl_keyboard *keyboard;
+
+
+};
+
+/** wayland window encompasing the display and shell surfaces */
+struct wld_window {
+ struct wld_connection* connection; /**< connection to wayland server */
+
+ struct wl_surface *surface; /**< drawing surface object */
+ struct wl_shell_surface *shell_surface; /**< shell surface object */
+
+ int width, height;
+};
+
+struct wld_shm_buffer {
+ struct wl_buffer *buffer; /**< wayland buffer object */
+ void *data; /**< mapped memory */
+ int size; /**< size of mapped memory */
+ bool inuse; /**< flag to indicate if the buffer has been released
+ * after commit to a surface.
+ */
+};
+
+
+typedef struct wldstate_s {
+ struct wld_connection* connection; /**< connection to wayland server */
+ struct wld_window *window;
+ struct wld_shm_buffer *shm_buffer;
+} wldstate_t;
+
+
+#if 0
+
+#if defined(NSFB_NEED_HINTS_ALLOC)
+static xcb_size_hints_t *
+xcb_alloc_size_hints(void)
+{
+ return calloc(1, sizeof(xcb_size_hints_t));
+}
+
+static void
+xcb_free_size_hints(xcb_size_hints_t *hints)
+{
+ free(hints);
+}
+#endif
+
+#if defined(NSFB_NEED_ICCCM_API_PREFIX)
+#define xcb_size_hints_set_max_size xcb_icccm_size_hints_set_max_size
+#define xcb_size_hints_set_min_size xcb_icccm_size_hints_set_min_size
+#define xcb_set_wm_size_hints xcb_icccm_set_wm_size_hints
+#endif
+
+#if (NSFB_XCBPROTO_MAJOR_VERSION > 1) || \
+ (NSFB_XCBPROTO_MAJOR_VERSION == 1 && NSFB_XCBPROTO_MINOR_VERSION >= 6)
+#define WM_NORMAL_HINTS XCB_ATOM_WM_NORMAL_HINTS
+#endif
+
+#define X_BUTTON_LEFT 1
+#define X_BUTTON_MIDDLE 2
+#define X_BUTTON_RIGHT 3
+#define X_BUTTON_WHEELUP 4
+#define X_BUTTON_WHEELDOWN 5
+
+typedef struct xstate_s {
+ xcb_connection_t *connection; /* The x server connection */
+ xcb_screen_t *screen; /* The screen to put the window on */
+ xcb_key_symbols_t *keysymbols; /* keysym mappings */
+
+ xcb_shm_segment_info_t shminfo;
+
+ xcb_image_t *image; /* The X image buffer */
+
+ xcb_window_t window; /* The handle to the window */
+ xcb_pixmap_t pmap; /* The handle to the backing pixmap */
+ xcb_gcontext_t gc; /* The handle to the pixmap plotting graphics context */
+ xcb_shm_seg_t segment; /* The handle to the image shared memory */
+} xstate_t;
+
+/* X keyboard codepage to nsfb mapping*/
+static enum nsfb_key_code_e XCSKeyboardMap[256] = {
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_BACKSPACE, /* XK_BackSpace */
+ NSFB_KEY_TAB, /* XK_Tab */
+ NSFB_KEY_UNKNOWN, /* XK_Linefeed */
+ NSFB_KEY_CLEAR, /* XK_Clear */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_RETURN, /* XK_Return */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x10 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_PAUSE, /* XK_Pause */
+ NSFB_KEY_UNKNOWN, /* XK_Scroll_Lock */
+ NSFB_KEY_UNKNOWN, /* XK_Sys_Req */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_ESCAPE, /* XK_Escape */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x20 */
+ NSFB_KEY_UNKNOWN, /* XK_Multi_key */
+ NSFB_KEY_UNKNOWN, /* XK_Kanji */
+ NSFB_KEY_UNKNOWN, /* XK_Muhenkan */
+ NSFB_KEY_UNKNOWN, /* XK_Henkan_Mode */
+ NSFB_KEY_UNKNOWN, /* XK_Henkan */
+ NSFB_KEY_UNKNOWN, /* XK_Romaji */
+ NSFB_KEY_UNKNOWN, /* XK_Hiragana*/
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x30 */
+ NSFB_KEY_UNKNOWN, /* XK_Eisu_toggle */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_Codeinput */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_SingleCandidate */
+ NSFB_KEY_UNKNOWN, /* XK_MultipleCandidate */
+ NSFB_KEY_UNKNOWN, /* XK_PreviousCandidate */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x40 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x50 */
+ NSFB_KEY_HOME, /* XK_Home */
+ NSFB_KEY_LEFT, /* XK_Left */
+ NSFB_KEY_UP, /* XK_Up */
+ NSFB_KEY_RIGHT, /* XK_Right */
+ NSFB_KEY_DOWN, /* XK_Down */
+ NSFB_KEY_PAGEUP, /* XK_Page_Up */
+ NSFB_KEY_PAGEDOWN, /* XK_Page_Down */
+ NSFB_KEY_END, /* XK_End */
+ NSFB_KEY_UNKNOWN, /* XK_Begin */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x60 */
+ NSFB_KEY_UNKNOWN, /* XK_Select */
+ NSFB_KEY_UNKNOWN, /* XK_Print*/
+ NSFB_KEY_UNKNOWN, /* XK_Execute*/
+ NSFB_KEY_UNKNOWN, /* XK_Insert*/
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_Undo*/
+ NSFB_KEY_UNKNOWN, /* XK_Redo */
+ NSFB_KEY_UNKNOWN, /* XK_Menu */
+ NSFB_KEY_UNKNOWN, /* XK_Find */
+ NSFB_KEY_UNKNOWN, /* XK_Cancel */
+ NSFB_KEY_UNKNOWN, /* XK_Help */
+ NSFB_KEY_UNKNOWN, /* XK_Break*/
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x70 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_Mode_switch */
+ NSFB_KEY_UNKNOWN, /* XK_Num_Lock */
+ /* 0x80 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_Space */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_KP_Tab */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_KP_Enter */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0x90 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_KP_F1*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_F2*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_F3*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_F4*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Home*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Left*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Up*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Right*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Down*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Page_Up*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Page_Down*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_End*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Begin*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Insert*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Delete*/
+ /* 0xa0 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_KP_Multiply*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Add*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Separator*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Subtract*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Decimal*/
+ NSFB_KEY_UNKNOWN, /* XK_KP_Divide*/
+ /* 0xb0 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_0 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_1 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_2 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_3 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_4 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_5 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_6 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_7 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_8 */
+ NSFB_KEY_UNKNOWN, /* XK_KP_9 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_F1, /* XK_F1 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* XK_KP_Equal */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_F2, /* XK_F2 */
+ /* 0xc0 */
+ NSFB_KEY_F3, /* XK_F3*/
+ NSFB_KEY_F4, /* XK_F4*/
+ NSFB_KEY_F5, /* XK_F5*/
+ NSFB_KEY_F6, /* XK_F6*/
+ NSFB_KEY_F7, /* XK_F7*/
+ NSFB_KEY_F8, /* XK_F8*/
+ NSFB_KEY_F9, /* XK_F9*/
+ NSFB_KEY_F10, /* XK_F10*/
+ NSFB_KEY_F11, /* XK_F11*/
+ NSFB_KEY_F12, /* XK_F12*/
+ NSFB_KEY_F13, /* XK_F13 */
+ NSFB_KEY_F14, /* XK_F14 */
+ NSFB_KEY_F15, /* XK_F15 */
+ NSFB_KEY_UNKNOWN, /* XK_F16 */
+ NSFB_KEY_UNKNOWN, /* XK_F17 */
+ NSFB_KEY_UNKNOWN, /* XK_F18*/
+ /* 0xd0 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0xe0 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_LSHIFT, /* XK_Shift_L*/
+ NSFB_KEY_RSHIFT, /* XK_Shift_R*/
+ NSFB_KEY_UNKNOWN, /* XK_Control_L*/
+ NSFB_KEY_UNKNOWN, /* XK_Control_R*/
+ NSFB_KEY_UNKNOWN, /* XK_Caps_Lock*/
+ NSFB_KEY_UNKNOWN, /* XK_Shift_Lock*/
+ NSFB_KEY_UNKNOWN, /* XK_Meta_L*/
+ NSFB_KEY_UNKNOWN, /* XK_Meta_R*/
+ NSFB_KEY_UNKNOWN, /* XK_Alt_L */
+ NSFB_KEY_UNKNOWN, /* XK_Alt_R*/
+ NSFB_KEY_UNKNOWN, /* XK_Super_L*/
+ NSFB_KEY_UNKNOWN, /* XK_Super_R*/
+ NSFB_KEY_UNKNOWN, /* XK_Hyper_L*/
+ NSFB_KEY_UNKNOWN, /* XK_Hyper_R*/
+ NSFB_KEY_UNKNOWN, /* */
+ /* 0xf0 */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+ NSFB_KEY_UNKNOWN, /* */
+};
+
+/* Convert an X keysym into a nsfb key code.
+ *
+ * Our approach is primarily to assume both codings are roughly ascii like.
+ *
+ * The Keysyms are defined in X11/keysymdef.h and our mapping for the
+ * "keyboard" keys i.e. those from code set 255 is from there
+ */
+static enum nsfb_key_code_e
+xkeysym_to_nsfbkeycode(xcb_keysym_t ks)
+{
+ enum nsfb_key_code_e nsfb_key = NSFB_KEY_UNKNOWN;
+ uint8_t codeset = (ks & 0xFF00) >> 8;
+ uint8_t chrcode = ks & 0xFF;
+
+ if (ks != XCB_NO_SYMBOL) {
+
+ switch (codeset) {
+ case 0x00: /* Latin 1 */
+ case 0x01: /* Latin 2 */
+ case 0x02: /* Latin 3 */
+ case 0x03: /* Latin 4 */
+ case 0x04: /* Katakana */
+ case 0x05: /* Arabic */
+ case 0x06: /* Cyrillic */
+ case 0x07: /* Greek */
+ case 0x08: /* Technical */
+ case 0x0A: /* Publishing */
+ case 0x0C: /* Hebrew */
+ case 0x0D: /* Thai */
+ /* this is somewhat incomplete, but the nsfb codes are lined up on
+ * the ascii codes and x seems to have done similar
+ */
+ nsfb_key = (enum nsfb_key_code_e)chrcode;
+ break;
+
+ case 0xFF: /* Keyboard */
+ nsfb_key = XCSKeyboardMap[chrcode];
+ break;
+ }
+ }
+
+ return nsfb_key;
+}
+/*
+ static void
+ set_palette(nsfb_t *nsfb)
+ {
+ X_Surface *x_screen = nsfb->surface_priv;
+ X_Color palette[256];
+ int rloop, gloop, bloop;
+ int loop = 0;
+
+ // build a linear R:3 G:3 B:2 colour cube palette.
+ for (rloop = 0; rloop < 8; rloop++) {
+ for (gloop = 0; gloop < 8; gloop++) {
+ for (bloop = 0; bloop < 4; bloop++) {
+ palette[loop].r = (rloop << 5) | (rloop << 2) | (rloop >> 1);
+ palette[loop].g = (gloop << 5) | (gloop << 2) | (gloop >> 1);
+ palette[loop].b = (bloop << 6) | (bloop << 4) | (bloop << 2) | (bloop);
+ nsfb->palette[loop] = palette[loop].r |
+ palette[loop].g << 8 |
+ palette[loop].b << 16;
+ loop++;
+ }
+ }
+ }
+
+ // Set palette
+ //X_SetColors(x_screen, palette, 0, 256);
+
+ }
+*/
+static int
+update_pixmap(xstate_t *xstate, int x, int y, int width, int height)
+{
+ if (xstate->shminfo.shmseg == 0) {
+ /* not using shared memory */
+ xcb_put_image(xstate->connection,
+ xstate->image->format,
+ xstate->pmap,
+ xstate->gc,
+ xstate->image->width,
+ height,
+ 0,
+ y,
+ 0,
+ xstate->image->depth,
+ (height) * xstate->image->stride,
+ xstate->image->data + (y * xstate->image->stride));
+ } else {
+ /* shared memory */
+ xcb_image_shm_put(xstate->connection,
+ xstate->pmap,
+ xstate->gc,
+ xstate->image,
+ xstate->shminfo,
+ x,y,
+ x,y,
+ width,height,0);
+ }
+
+ return 0;
+}
+
+static int
+update_and_redraw_pixmap(xstate_t *xstate, int x, int y, int width, int height)
+{
+ update_pixmap(xstate, x, y, width, height);
+
+ xcb_copy_area(xstate->connection,
+ xstate->pmap,
+ xstate->window,
+ xstate->gc,
+ x, y,
+ x, y,
+ width, height);
+
+ xcb_flush(xstate->connection);
+
+ return 0;
+}
+
+
+static bool
+xcopy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
+{
+ xstate_t *xstate = nsfb->surface_priv;
+ nsfb_bbox_t allbox;
+ struct nsfb_cursor_s *cursor = nsfb->cursor;
+ uint8_t *srcptr;
+ uint8_t *dstptr;
+ int srcx = srcbox->x0;
+ int srcy = srcbox->y0;
+ int dstx = dstbox->x0;
+ int dsty = dstbox->y0;
+ int width = dstbox->x1 - dstbox->x0;
+ int height = dstbox->y1 - dstbox->y0;
+ int hloop;
+
+ nsfb_plot_add_rect(srcbox, dstbox, &allbox);
+
+ /* clear the cursor if its within the region to be altered */
+ if ((cursor != NULL) &&
+ (cursor->plotted == true) &&
+ (nsfb_plot_bbox_intersect(&allbox, &cursor->loc))) {
+
+ nsfb_cursor_clear(nsfb, cursor);
+ update_pixmap(xstate,
+ cursor->savloc.x0,
+ cursor->savloc.y0,
+ cursor->savloc.x1 - cursor->savloc.x0,
+ cursor->savloc.y1 - cursor->savloc.y0);
+
+ /* must sync here or local framebuffer and remote pixmap will not be
+ * consistant
+ */
+ xcb_aux_sync(xstate->connection);
+
+ }
+
+ /* copy the area on the server */
+ xcb_copy_area(xstate->connection,
+ xstate->pmap,
+ xstate->pmap,
+ xstate->gc,
+ srcbox->x0,
+ srcbox->y0,
+ dstbox->x0,
+ dstbox->y0,
+ srcbox->x1 - srcbox->x0,
+ srcbox->y1 - srcbox->y0);
+
+ /* do the copy in the local memory too */
+ srcptr = (nsfb->ptr +
+ (srcy * nsfb->linelen) +
+ ((srcx * nsfb->bpp) / 8));
+
+ dstptr = (nsfb->ptr +
+ (dsty * nsfb->linelen) +
+ ((dstx * nsfb->bpp) / 8));
+
+ if (width == nsfb->width) {
+ /* take shortcut and use memmove */
+ memmove(dstptr, srcptr, (width * height * nsfb->bpp) / 8);
+ } else {
+ if (srcy > dsty) {
+ for (hloop = height; hloop > 0; hloop--) {
+ memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
+ srcptr += nsfb->linelen;
+ dstptr += nsfb->linelen;
+ }
+ } else {
+ srcptr += height * nsfb->linelen;
+ dstptr += height * nsfb->linelen;
+ for (hloop = height; hloop > 0; hloop--) {
+ srcptr -= nsfb->linelen;
+ dstptr -= nsfb->linelen;
+ memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
+ }
+ }
+ }
+
+ if ((cursor != NULL) &&
+ (cursor->plotted == false)) {
+ nsfb_cursor_plot(nsfb, cursor);
+ }
+
+ /* update the x window */
+ xcb_copy_area(xstate->connection,
+ xstate->pmap,
+ xstate->window,
+ xstate->gc,
+ dstx, dsty,
+ dstx, dsty,
+ width, height);
+
+ return true;
+
+}
+
+#endif
+
+
+static int
+wld_set_geometry(nsfb_t *nsfb, int width, int height, enum nsfb_format_e format)
+{
+ if (nsfb->surface_priv != NULL)
+ return -1; /* if were already initialised fail */
+
+ nsfb->width = width;
+ nsfb->height = height;
+ nsfb->format = format;
+
+ /* select default sw plotters for format */
+ select_plotters(nsfb);
+
+}
+
+#if 0
+
+
+static xcb_format_t *
+find_format(xcb_connection_t * c, uint8_t depth, uint8_t bpp)
+{
+ const xcb_setup_t *setup = xcb_get_setup(c);
+ xcb_format_t *fmt = xcb_setup_pixmap_formats(setup);
+ xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
+
+ for(; fmt != fmtend; ++fmt) {
+ if((fmt->depth == depth) && (fmt->bits_per_pixel == bpp)) {
+ return fmt;
+ }
+ }
+ return 0;
+}
+
+static xcb_image_t *
+create_shm_image(xstate_t *xstate, int width, int height, int bpp)
+{
+ const xcb_setup_t *setup = xcb_get_setup(xstate->connection);
+ unsigned char *image_data;
+ xcb_format_t *fmt;
+ int depth = bpp;
+ uint32_t image_size;
+ int shmid;
+
+ xcb_shm_query_version_reply_t *rep;
+ xcb_shm_query_version_cookie_t ck;
+ xcb_void_cookie_t shm_attach_cookie;
+ xcb_generic_error_t *generic_error;
+
+ ck = xcb_shm_query_version(xstate->connection);
+ rep = xcb_shm_query_version_reply(xstate->connection, ck , NULL);
+ if (!rep) {
+ fprintf (stderr, "Server has no shm support.\n");
+ return NULL;
+ }
+
+ if ((rep->major_version < 1) ||
+ (rep->major_version == 1 && rep->minor_version == 0)) {
+ fprintf(stderr, "server SHM support is insufficient.\n");
+ free(rep);
+ return NULL;
+ }
+ free(rep);
+
+ if (bpp == 32)
+ depth = 24;
+
+ fmt = find_format(xstate->connection, depth, bpp);
+ if (fmt == NULL)
+ return NULL;
+
+ /* doing it this way ensures we deal with bpp smaller than 8 */
+ image_size = (bpp * width * height) >> 3;
+
+ /* get the shared memory segment */
+ shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT|0777);
+ if (shmid == -1)
+ return NULL;
+
+ xstate->shminfo.shmid = shmid;
+
+ xstate->shminfo.shmaddr = shmat(xstate->shminfo.shmid, 0, 0);
+ image_data = xstate->shminfo.shmaddr;
+
+ xstate->shminfo.shmseg = xcb_generate_id(xstate->connection);
+ shm_attach_cookie = xcb_shm_attach_checked(xstate->connection,
+ xstate->shminfo.shmseg,
+ xstate->shminfo.shmid,
+ 0);
+ generic_error = xcb_request_check(xstate->connection, shm_attach_cookie);
+
+ /* either there is an error and the shm us no longer needed, or it now
+ * belongs to the x server - regardless release local reference to shared
+ * memory segment
+ */
+ shmctl(xstate->shminfo.shmid, IPC_RMID, 0);
+
+ if (generic_error != NULL) {
+ /* unable to attach shm */
+ xstate->shminfo.shmseg = 0;
+
+ free(generic_error);
+ return NULL;
+ }
+
+
+ return xcb_image_create(width,
+ height,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ fmt->scanline_pad,
+ fmt->depth,
+ fmt->bits_per_pixel,
+ 0,
+ setup->image_byte_order,
+ XCB_IMAGE_ORDER_LSB_FIRST,
+ image_data,
+ image_size,
+ image_data);
+}
+
+
+static xcb_image_t *
+create_image(xcb_connection_t *c, int width, int height, int bpp)
+{
+ const xcb_setup_t *setup = xcb_get_setup(c);
+ unsigned char *image_data;
+ xcb_format_t *fmt;
+ int depth = bpp;
+ uint32_t image_size;
+
+ if (bpp == 32)
+ depth = 24;
+
+ fmt = find_format(c, depth, bpp);
+ if (fmt == NULL)
+ return NULL;
+
+ /* doing it this way ensures we deal with bpp smaller than 8 */
+ image_size = (bpp * width * height) >> 3;
+
+ image_data = calloc(1, image_size);
+ if (image_data == NULL)
+ return NULL;
+
+ return xcb_image_create(width,
+ height,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ fmt->scanline_pad,
+ fmt->depth,
+ fmt->bits_per_pixel,
+ 0,
+ setup->image_byte_order,
+ XCB_IMAGE_ORDER_LSB_FIRST,
+ image_data,
+ image_size,
+ image_data);
+}
+
+/**
+ * Create a blank cursor.
+ * The empty pixmaps is leaked.
+ *
+ * @param conn xcb connection
+ * @param scr xcb XCB screen
+ */
+static xcb_cursor_t
+create_blank_cursor(xcb_connection_t *conn, const xcb_screen_t *scr)
+{
+ xcb_cursor_t cur = xcb_generate_id(conn);
+ xcb_pixmap_t pix = xcb_generate_id(conn);
+ xcb_void_cookie_t ck;
+ xcb_generic_error_t *err;
+
+ ck = xcb_create_pixmap_checked (conn, 1, pix, scr->root, 1, 1);
+ err = xcb_request_check (conn, ck);
+ if (err) {
+ fprintf (stderr, "Cannot create pixmap: %d", err->error_code);
+ free (err);
+ }
+ ck = xcb_create_cursor_checked (conn, cur, pix, pix, 0, 0, 0, 0, 0, 0, 0, 0);
+ err = xcb_request_check (conn, ck);
+ if (err) {
+ fprintf (stderr, "Cannot create cursor: %d", err->error_code);
+ free (err);
+ }
+ return cur;
+}
+#endif
+
+
+/** shared memory interface format available callback
+ *
+ * @param ctx context from when listener was added.
+ * @param wl_shm The shared memory object.
+ * @param format The available shared memory format. Found in
+ * wayland-client-protocol.h there are currently only two
+ * formats available (A|X)RGB8888 so using a bitfield is ok.
+ */
+static void
+shm_format(void *ctx, struct wl_shm *wl_shm, uint32_t format)
+{
+ struct wld_connection* connection = ctx;
+
+ connection->shm_formats |= (1 << format);
+}
+
+/** shared memory interface callback handlers */
+struct wl_shm_listener shm_listenter = {
+ shm_format
+};
+
+static void
+pointer_handle_enter(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface,
+ wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+#if 0
+ struct input *input = data;
+ struct window *window;
+ struct widget *widget;
+ float sx = wl_fixed_to_double(sx_w);
+ float sy = wl_fixed_to_double(sy_w);
+
+ if (!surface) {
+ /* enter event for a window we've just destroyed */
+ return;
+ }
+
+ input->display->serial = serial;
+ input->pointer_enter_serial = serial;
+ input->pointer_focus = wl_surface_get_user_data(surface);
+ window = input->pointer_focus;
+
+ if (window->resizing) {
+ window->resizing = 0;
+ /* Schedule a redraw to free the pool */
+ window_schedule_redraw(window);
+ }
+
+ input->sx = sx;
+ input->sy = sy;
+
+ widget = window_find_widget(window, sx, sy);
+ input_set_focus_widget(input, widget, sx, sy);
+
+#endif
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+#if 0
+ struct input *input = data;
+
+ input->display->serial = serial;
+ input_remove_pointer_focus(input);
+#endif
+}
+
+static void
+enqueue_wld_event(struct wld_connection *connection, struct wld_event* event)
+{
+ event->next = NULL;
+ if (connection->event_tail == NULL) {
+ connection->event_head = event;
+ connection->event_tail = event;
+ } else {
+ connection->event_tail->next = event;
+ connection->event_tail = event;
+ }
+}
+
+static struct wld_event*
+dequeue_wld_event(struct wld_connection *connection)
+{
+ struct wld_event* event = connection->event_head;
+
+ if (event != NULL) {
+ connection->event_head = event->next;
+ if (connection->event_head == NULL) {
+ connection->event_tail = connection->event_head;
+ }
+ }
+ return event;
+}
+
+static void
+pointer_handle_motion(void *data,
+ struct wl_pointer *pointer,
+ uint32_t time,
+ wl_fixed_t sx_w,
+ wl_fixed_t sy_w)
+{
+ struct wld_input *input = data;
+ struct wld_event *event;
+
+ event = calloc(1, sizeof(struct wld_event));
+
+ event->event.type = NSFB_EVENT_MOVE_ABSOLUTE;
+ event->event.value.vector.x = wl_fixed_to_int(sx_w);
+ event->event.value.vector.y = wl_fixed_to_int(sy_w);
+ event->event.value.vector.z = 0;
+
+ enqueue_wld_event(input->connection, event);
+}
+
+static void
+pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state_w)
+{
+ struct wld_input *input = data;
+ struct wld_event *event;
+ enum wl_pointer_button_state state = state_w;
+
+ event = calloc(1, sizeof(struct wld_event));
+
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ event->event.type = NSFB_EVENT_KEY_DOWN;
+ } else {
+ event->event.type = NSFB_EVENT_KEY_UP;
+ }
+
+ switch (button) {
+ case BTN_LEFT:
+ event->event.value.keycode = NSFB_KEY_MOUSE_1;
+ break;
+ case BTN_MIDDLE:
+ event->event.value.keycode = NSFB_KEY_MOUSE_2;
+ break;
+ case BTN_RIGHT:
+ event->event.value.keycode = NSFB_KEY_MOUSE_3;
+ break;
+ case BTN_FORWARD:
+ event->event.value.keycode = NSFB_KEY_MOUSE_4;
+ break;
+ case BTN_BACK:
+ event->event.value.keycode = NSFB_KEY_MOUSE_5;
+ break;
+ }
+
+ enqueue_wld_event(input->connection, event);
+
+
+#if 0
+ struct input *input = data;
+ struct widget *widget;
+ enum wl_pointer_button_state state = state_w;
+
+ input->display->serial = serial;
+ if (input->focus_widget && input->grab == NULL &&
+ state == WL_POINTER_BUTTON_STATE_PRESSED)
+ input_grab(input, input->focus_widget, button);
+
+ widget = input->grab;
+ if (widget && widget->button_handler)
+ (*widget->button_handler)(widget,
+ input, time,
+ button, state,
+ input->grab->user_data);
+
+ if (input->grab && input->grab_button == button &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED)
+ input_ungrab(input);
+#endif
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+#if 0
+ struct input *input = data;
+ struct widget *widget;
+
+ widget = input->focus_widget;
+ if (input->grab)
+ widget = input->grab;
+ if (widget && widget->axis_handler)
+ (*widget->axis_handler)(widget,
+ input, time,
+ axis, value,
+ widget->user_data);
+#endif
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+};
+
+static void
+seat_handle_capabilities(void *data,
+ struct wl_seat *seat,
+ enum wl_seat_capability caps)
+{
+ struct wld_input *input = data;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
+ input->pointer = wl_seat_get_pointer(seat);
+
+ wl_pointer_add_listener(input->pointer, &pointer_listener, input);
+
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
+
+ wl_pointer_destroy(input->pointer);
+ input->pointer = NULL;
+ }
+
+#if 0
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
+ input->keyboard = wl_seat_get_keyboard(seat);
+
+ wl_keyboard_add_listener(input->keyboard, &keyboard_listener, input);
+
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
+
+ wl_keyboard_destroy(input->keyboard);
+ input->keyboard = NULL;
+ }
+#endif
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_handle_capabilities,
+};
+
+/**
+ * new seat added
+ */
+static struct wld_input *
+new_input_seat(struct wld_connection *connection,
+ struct wl_registry *registry,
+ uint32_t id)
+{
+ struct wld_input *input;
+
+ input = calloc(1, sizeof(struct wld_input));
+ if (input == NULL) {
+ return NULL;
+ }
+
+ input->connection = connection;
+
+ input->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
+ if (input->seat == NULL) {
+ free(input);
+ return NULL;
+ }
+
+ wl_seat_add_listener(input->seat, &seat_listener, input);
+
+ return input;
+}
+
+/** registry global addition callback
+ *
+ * @param ctx context from when listener was added
+ */
+static void
+registry_handle_global(void *ctx,
+ struct wl_registry *registry,
+ uint32_t id,
+ const char *interface,
+ uint32_t version)
+{
+ struct wld_connection* connection = ctx;
+
+ /* process new interfaces appearing on the global registry */
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ /* compositor interface is available. Bind the interface */
+ connection->compositor = wl_registry_bind(registry,
+ id,
+ &wl_compositor_interface,
+ 1);
+
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ /* shell interface is available. Bind the interface */
+ connection->shell = wl_registry_bind(registry,
+ id,
+ &wl_shell_interface,
+ 1);
+
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ /* shared memory interface is available. Bind the interface
+ * and add a listener for the shared memory callbacks
+ */
+ connection->shm = wl_registry_bind(registry,
+ id,
+ &wl_shm_interface,
+ 1);
+ if (connection->shm != NULL) {
+ connection->shm_formats = 0;
+ wl_shm_add_listener(connection->shm, &shm_listenter, connection);
+ }
+
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ struct wld_input *input;
+
+ input = new_input_seat(connection, registry, id);
+ if (input != NULL) {
+ wl_list_insert(connection->input_list.prev, &input->link);
+ }
+ }
+}
+
+/** registry global removal callback */
+static void
+registry_handle_global_remove(void *data,
+ struct wl_registry *registry,
+ uint32_t name)
+{
+}
+
+/** registry global callback handlers */
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+
+static void
+free_connection(struct wld_connection* connection)
+{
+ if (connection->compositor != NULL) {
+ wl_compositor_destroy(connection->compositor);
+ }
+
+ if (connection->shell != NULL) {
+ wl_shell_destroy(connection->shell);
+ }
+
+ if (connection->shm != NULL) {
+ wl_shm_destroy(connection->shm);
+ }
+
+ wl_registry_destroy(connection->registry);
+
+ wl_display_flush(connection->display);
+
+ wl_display_disconnect(connection->display);
+
+ free(connection);
+}
+
+/** construct a new connection to the wayland instance and aquire all
+ * necessary global objects
+ */
+static struct wld_connection*
+new_connection(void)
+{
+ struct wld_connection* connection;
+
+ connection = calloc(1, sizeof(struct wld_connection));
+
+ if (connection == NULL) {
+ return NULL;
+ }
+
+ /* initialise lists */
+ wl_list_init(&connection->input_list);
+
+ /* make a connection to the wayland server */
+ connection->display = wl_display_connect(NULL);
+ if (connection->display == NULL) {
+ fprintf(stderr, "Unable to open display\n");
+ free(connection);
+ return NULL;
+ }
+
+ /* create the registry object and attach its callback handlers */
+ connection->registry = wl_display_get_registry(connection->display);
+ if (connection->registry == NULL) {
+ fprintf(stderr, "Unable create registry\n");
+ wl_display_flush(connection->display);
+ wl_display_disconnect(connection->display);
+ free(connection);
+ return NULL;
+ }
+
+ wl_registry_add_listener(connection->registry,
+ &registry_listener,
+ connection);
+ /* perform a round trip to ensure registry messages have been processed */
+ wl_display_roundtrip(connection->display);
+
+ /* all global objects from the registry should now be available. */
+
+ if (connection->shm == NULL) {
+ /* The shared memory interface is available so fail. */
+ fprintf(stderr, "No shared memory interface available\n");
+
+ free_connection(connection);
+
+ return NULL;
+ }
+
+ /* perform a round trip to ensure interface messages have been processed */
+ wl_display_roundtrip(connection->display);
+
+ /* check the XRGB8888 shared memory format is available */
+ if (!(connection->shm_formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
+ fprintf(stderr, "WL_SHM_FORMAT_XRGB8888 not available\n");
+
+ free_connection(connection);
+
+ return NULL;
+ }
+
+ return connection;
+}
+
+
+
+static int
+update_and_redraw(struct wldstate_s *wldstate,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ wl_surface_attach(wldstate->window->surface,
+ wldstate->shm_buffer->buffer,
+ 0,
+ 0);
+
+ wl_surface_damage(wldstate->window->surface, x, y, width, height);
+
+ wl_surface_commit(wldstate->window->surface);
+ wldstate->shm_buffer->inuse = true;
+
+ /* force syncronisation to cause the update */
+ wl_display_roundtrip(wldstate->connection->display);
+
+ return 0;
+}
+
+static void
+handle_ping(void *data, struct wl_shell_surface *shell_surface,
+ uint32_t serial)
+{
+ wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void
+handle_configure(void *data, struct wl_shell_surface *shell_surface,
+ uint32_t edges, int32_t width, int32_t height)
+{
+}
+
+static void
+handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+ handle_ping,
+ handle_configure,
+ handle_popup_done
+};
+
+static struct wld_window *
+new_window(struct wld_connection *connection, int width, int height)
+{
+ struct wld_window *window;
+
+ window = calloc(1, sizeof *window);
+ if (window == NULL) {
+ return NULL;
+ }
+
+ window->connection = connection;
+ window->width = width;
+ window->height = height;
+
+ window->surface = wl_compositor_create_surface(connection->compositor);
+ if (window->surface == NULL) {
+ fprintf(stderr, "failed to create compositor surface\n");
+ free(window);
+ return NULL;
+ }
+
+ window->shell_surface = wl_shell_get_shell_surface(connection->shell,
+ window->surface);
+ if (window->shell_surface == NULL) {
+ fprintf(stderr, "failed to create shell surface\n");
+
+ wl_surface_destroy(window->surface);
+
+ free(window);
+ return NULL;
+ }
+
+ wl_shell_surface_add_listener(window->shell_surface,
+ &shell_surface_listener, window);
+
+ wl_shell_surface_set_title(window->shell_surface, "nsfb");
+
+ wl_shell_surface_set_toplevel(window->shell_surface);
+
+ return window;
+}
+
+static void
+free_window(struct wld_window *window)
+{
+
+ wl_shell_surface_destroy(window->shell_surface);
+ wl_surface_destroy(window->surface);
+
+ free(window);
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ */
+static int
+os_create_anonymous_file(off_t size)
+{
+ static const char template[] = "/weston-shared-XXXXXX";
+ const char *path;
+ char *name;
+ int fd;
+
+ path = getenv("XDG_RUNTIME_DIR");
+ if (!path) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ name = malloc(strlen(path) + sizeof(template));
+ if (!name)
+ return -1;
+
+ strcpy(name, path);
+ strcat(name, template);
+
+ fd = mkostemp(name, O_CLOEXEC);
+ if (fd >= 0)
+ unlink(name);
+
+ free(name);
+
+ if (fd < 0)
+ return -1;
+
+ if (ftruncate(fd, size) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+
+static void
+buffer_release(void *data, struct wl_buffer *buffer)
+{
+ struct wld_shm_buffer *shmbuf = data;
+
+ shmbuf->inuse = false;
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ buffer_release
+};
+
+static struct wld_shm_buffer *
+new_shm_buffer(struct wl_shm *shm,
+ int width,
+ int height,
+ uint32_t format)
+{
+ struct wl_shm_pool *pool;
+ struct wld_shm_buffer *shmbuff;
+ int fd;
+ int stride;
+
+ shmbuff = calloc(1, sizeof(struct wld_shm_buffer));
+ if (shmbuff == NULL) {
+ return NULL;
+ }
+
+ stride = width * 4;
+ shmbuff->size = stride * height;
+
+ fd = os_create_anonymous_file(shmbuff->size);
+ if (fd < 0) {
+ free(shmbuff);
+ return NULL;
+ }
+
+ shmbuff->data = mmap(NULL,
+ shmbuff->size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (shmbuff->data == MAP_FAILED) {
+ close(fd);
+ free(shmbuff);
+ return NULL;
+ }
+
+ pool = wl_shm_create_pool(shm, fd, shmbuff->size);
+ shmbuff->buffer = wl_shm_pool_create_buffer(pool,
+ 0,
+ width,
+ height,
+ stride,
+ format);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ if (shmbuff->buffer == NULL) {
+ munmap(shmbuff->data, shmbuff->size);
+ free(shmbuff);
+ return NULL;
+ }
+
+ wl_buffer_add_listener(shmbuff->buffer, &buffer_listener, shmbuff);
+
+ return shmbuff;
+}
+
+static void free_shm_buffer(struct wld_shm_buffer *shmbuf)
+{
+ munmap(shmbuf->data, shmbuf->size);
+ free(shmbuf);
+}
+
+static int wld_initialise(nsfb_t *nsfb)
+{
+ wldstate_t *wldstate = nsfb->surface_priv;
+
+ if (wldstate != NULL)
+ return -1; /* already initialised */
+
+ /* check bpp is what we can support. */
+ if (nsfb->bpp != 32) {
+ return -1;
+ }
+
+ wldstate = calloc(1, sizeof(wldstate_t));
+ if (wldstate == NULL) {
+ return -1; /* no memory */
+ }
+
+ wldstate->connection = new_connection();
+ if (wldstate->connection == NULL) {
+ fprintf(stderr, "Error initialising wayland connection\n");
+
+ free(wldstate);
+
+ return -1; /* error */
+ }
+
+ wldstate->window = new_window(wldstate->connection,
+ nsfb->width,
+ nsfb->height);
+ if (wldstate->window == NULL) {
+ fprintf(stderr, "Error creating wayland window\n");
+
+ free_connection(wldstate->connection);
+
+ free(wldstate);
+
+ return -1; /* error */
+ }
+
+ wldstate->shm_buffer = new_shm_buffer(wldstate->connection->shm,
+ nsfb->width,
+ nsfb->height,
+ WL_SHM_FORMAT_XRGB8888);
+ if (wldstate->shm_buffer == NULL) {
+ fprintf(stderr, "Error creating wayland shared memory\n");
+
+ free_window(wldstate->window);
+
+ free_connection(wldstate->connection);
+
+ free(wldstate);
+
+ return -1; /* error */
+ }
+
+ nsfb->ptr = wldstate->shm_buffer->data;
+ nsfb->linelen = nsfb->width * 4;
+
+ update_and_redraw(wldstate,0,0, nsfb->width, nsfb->height);
+
+ nsfb->surface_priv = wldstate;
+
+ return 0;
+}
+
+static int wld_finalise(nsfb_t *nsfb)
+{
+ wldstate_t *wldstate = nsfb->surface_priv;
+
+ if (wldstate == NULL) {
+ return 0; /* not initialised */
+ }
+
+ free_shm_buffer(wldstate->shm_buffer);
+
+ free_window(wldstate->window);
+
+ free_connection(wldstate->connection);
+}
+
+#if 0
+static int x_initialise(nsfb_t *nsfb)
+{
+ uint32_t mask;
+ uint32_t values[3];
+ xcb_size_hints_t *hints;
+ xstate_t *xstate = nsfb->surface_priv;
+ xcb_cursor_t blank_cursor;
+
+ if (xstate != NULL)
+ return -1; /* already initialised */
+
+ /* sanity check bpp. */
+ if ((nsfb->bpp != 32) && (nsfb->bpp != 16) && (nsfb->bpp != 8))
+ return -1;
+
+ xstate = calloc(1, sizeof(xstate_t));
+ if (xstate == NULL)
+ return -1; /* no memory */
+
+ /* open connection with the server */
+ xstate->connection = xcb_connect(NULL, NULL);
+ if (xstate->connection == NULL) {
+ fprintf(stderr, "Memory error opening display\n");
+ free(xstate);
+ return -1; /* no memory */
+ }
+
+ if (xcb_connection_has_error(xstate->connection) != 0) {
+ fprintf(stderr, "Error opening display\n");
+ free(xstate);
+ return -1; /* no memory */
+ }
+
+ /* get screen */
+ xstate->screen = xcb_setup_roots_iterator(xcb_get_setup(xstate->connection)).data;
+
+ /* create image */
+ xstate->image = create_shm_image(xstate, nsfb->width, nsfb->height, nsfb->bpp);
+
+ if (xstate->image == NULL)
+ xstate->image = create_image(xstate->connection, nsfb->width, nsfb->height, nsfb->bpp);
+
+ if (xstate->image == NULL) {
+ fprintf(stderr, "Unable to create image\n");
+ free(xstate);
+ xcb_disconnect(xstate->connection);
+ return -1;
+ }
+
+ /* ensure plotting information is stored */
+ nsfb->surface_priv = xstate;
+ nsfb->ptr = xstate->image->data;
+ nsfb->linelen = xstate->image->stride;
+
+ /* get blank cursor */
+ blank_cursor = create_blank_cursor(xstate->connection, xstate->screen);
+
+ /* get keysymbol maps */
+ xstate->keysymbols = xcb_key_symbols_alloc(xstate->connection);
+
+ /* create window */
+ mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
+ values[0] = xstate->screen->white_pixel;
+ values[1] = XCB_EVENT_MASK_EXPOSURE |
+ XCB_EVENT_MASK_KEY_PRESS |
+ XCB_EVENT_MASK_KEY_RELEASE |
+ XCB_EVENT_MASK_BUTTON_PRESS |
+ XCB_EVENT_MASK_BUTTON_RELEASE |
+ XCB_EVENT_MASK_POINTER_MOTION;
+ values[2] = blank_cursor;
+
+ xstate->window = xcb_generate_id(xstate->connection);
+ xcb_create_window (xstate->connection,
+ XCB_COPY_FROM_PARENT,
+ xstate->window,
+ xstate->screen->root,
+ 0, 0, xstate->image->width, xstate->image->height, 1,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ xstate->screen->root_visual,
+ mask, values);
+ /* set size hits on window */
+ hints = xcb_alloc_size_hints();
+ xcb_size_hints_set_max_size(hints, xstate->image->width, xstate->image->height);
+ xcb_size_hints_set_min_size(hints, xstate->image->width, xstate->image->height);
+ xcb_set_wm_size_hints(xstate->connection, xstate->window, WM_NORMAL_HINTS, hints);
+ xcb_free_size_hints(hints);
+
+ /* create backing pixmap */
+ xstate->pmap = xcb_generate_id(xstate->connection);
+ xcb_create_pixmap(xstate->connection, 24, xstate->pmap, xstate->window, xstate->image->width, xstate->image->height);
+
+ /* create pixmap plot gc */
+ mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
+ values[0] = xstate->screen->black_pixel;
+ values[1] = 0xffffff;
+
+ xstate->gc = xcb_generate_id (xstate->connection);
+ xcb_create_gc(xstate->connection, xstate->gc, xstate->pmap, mask, values);
+
+ /* if (nsfb->bpp == 8)
+ set_palette(nsfb);
+ */
+
+ /* put the image into the pixmap */
+ update_and_redraw_pixmap(xstate, 0, 0, xstate->image->width, xstate->image->height);
+
+
+ /* show the window */
+ xcb_map_window (xstate->connection, xstate->window);
+ xcb_flush(xstate->connection);
+
+ return 0;
+}
+
+static int x_finalise(nsfb_t *nsfb)
+{
+ xstate_t *xstate = nsfb->surface_priv;
+ if (xstate == NULL)
+ return 0;
+
+ xcb_key_symbols_free(xstate->keysymbols);
+
+ /* free pixmap */
+ xcb_free_pixmap(xstate->connection, xstate->pmap);
+
+ /* close connection to server */
+ xcb_disconnect(xstate->connection);
+
+ return 0;
+}
+#endif
+
+static bool wld_input(nsfb_t *nsfb, nsfb_event_t *event, int timeout)
+{
+ wldstate_t *wldstate = nsfb->surface_priv;
+ int ret = 0; /* number of events dispatched */
+ struct wld_event* wldevent; /* input event off queue */
+
+ if (wldstate == NULL) {
+ return false;
+ }
+
+ /* flush any pending outgoing messages to server */
+ wl_display_flush(wldstate->connection->display);
+
+ /* if there are queued input events, return them first */
+ wldevent = dequeue_wld_event(wldstate->connection);
+ if (wldevent != NULL) {
+ *event = wldevent->event;
+ free(wldevent);
+ return true;
+ }
+
+ if (timeout < 0) {
+ /* caller wants to wait forever for an event */
+ ret = wl_display_dispatch(wldstate->connection->display);
+ } else {
+ int confd;
+ fd_set rfds;
+ struct timeval tv;
+ int retval;
+
+ confd = wl_display_get_fd(wldstate->connection->display);
+
+ FD_ZERO(&rfds);
+ FD_SET(confd, &rfds);
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000;
+
+ retval = select(confd + 1, &rfds, NULL, NULL, &tv);
+ if (retval == 0) {
+ /* timeout, nothing ready to read */
+ ret = wl_display_dispatch_pending(wldstate->connection->display);
+ } else {
+ ret = wl_display_dispatch(wldstate->connection->display);
+ }
+ }
+
+ /* check for connection error */
+ if (ret == -1) {
+ /* exit on conenction error */
+ event->type = NSFB_EVENT_CONTROL;
+ event->value.controlcode = NSFB_CONTROL_QUIT;
+ return true;
+
+ } else if (ret == 0) {
+ /* timeout and no messages were processed and the input queue was
+ * empty on entry
+ */
+ event->type = NSFB_EVENT_CONTROL;
+ event->value.controlcode = NSFB_CONTROL_TIMEOUT;
+ return true;
+ }
+
+ /* messages were processed, they might have been input events */
+
+ wldevent = dequeue_wld_event(wldstate->connection);
+ if (wldevent == NULL) {
+ /* messages were not input events so signal no event */
+ return false;
+ }
+
+ *event = wldevent->event;
+
+ free(wldevent);
+
+ return true;
+}
+
+#if 0
+static bool x_input(nsfb_t *nsfb, nsfb_event_t *event, int timeout)
+{
+ xcb_generic_event_t *e;
+ xcb_expose_event_t *ee;
+ xcb_motion_notify_event_t *emn;
+ xcb_button_press_event_t *ebp;
+ xcb_key_press_event_t *ekp;
+ xcb_key_press_event_t *ekr;
+ xstate_t *xstate = nsfb->surface_priv;
+
+ if (xstate == NULL)
+ return false;
+
+ xcb_flush(xstate->connection);
+
+ /* try and retrive an event immediately */
+ e = xcb_poll_for_event(xstate->connection);
+
+ if ((e == NULL) && (timeout != 0)) {
+ if (timeout > 0) {
+ int confd;
+ fd_set rfds;
+ struct timeval tv;
+ int retval;
+
+ confd = xcb_get_file_descriptor(xstate->connection);
+ FD_ZERO(&rfds);
+ FD_SET(confd, &rfds);
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000;
+
+ retval = select(confd + 1, &rfds, NULL, NULL, &tv);
+ if (retval == 0) {
+ /* timeout, nothing happened */
+ event->type = NSFB_EVENT_CONTROL;
+ event->value.controlcode = NSFB_CONTROL_TIMEOUT;
+ return true;
+ }
+ }
+ e = xcb_wait_for_event(xstate->connection);
+ }
+
+ if (e == NULL) {
+ if (xcb_connection_has_error(xstate->connection) != 0) {
+ /* connection closed quiting time */
+ event->type = NSFB_EVENT_CONTROL;
+ event->value.controlcode = NSFB_CONTROL_QUIT;
+ return true;
+ } else {
+ return false; /* no event */
+ }
+ }
+
+ event->type = NSFB_EVENT_NONE;
+
+ switch (e->response_type) {
+ case XCB_EXPOSE:
+ ee = (xcb_expose_event_t *)e;
+ xcb_copy_area(xstate->connection,
+ xstate->pmap,
+ xstate->window,
+ xstate->gc,
+ ee->x, ee->y,
+ ee->x, ee->y,
+ ee->width, ee->height);
+ xcb_flush (xstate->connection);
+ break;
+
+ case XCB_MOTION_NOTIFY:
+ emn = (xcb_motion_notify_event_t *)e;
+ event->type = NSFB_EVENT_MOVE_ABSOLUTE;
+ event->value.vector.x = emn->event_x;
+ event->value.vector.y = emn->event_y;
+ event->value.vector.z = 0;
+ break;
+
+
+ case XCB_BUTTON_PRESS:
+ ebp = (xcb_button_press_event_t *)e;
+ event->type = NSFB_EVENT_KEY_DOWN;
+
+ switch (ebp->detail) {
+
+ case X_BUTTON_LEFT:
+ event->value.keycode = NSFB_KEY_MOUSE_1;
+ break;
+
+ case X_BUTTON_MIDDLE:
+ event->value.keycode = NSFB_KEY_MOUSE_2;
+ break;
+
+ case X_BUTTON_RIGHT:
+ event->value.keycode = NSFB_KEY_MOUSE_3;
+ break;
+
+ case X_BUTTON_WHEELUP:
+ event->value.keycode = NSFB_KEY_MOUSE_4;
+ break;
+
+ case X_BUTTON_WHEELDOWN:
+ event->value.keycode = NSFB_KEY_MOUSE_5;
+ break;
+ }
+ break;
+
+ case XCB_BUTTON_RELEASE:
+ ebp = (xcb_button_press_event_t *)e;
+ event->type = NSFB_EVENT_KEY_UP;
+
+ switch (ebp->detail) {
+
+ case X_BUTTON_LEFT:
+ event->value.keycode = NSFB_KEY_MOUSE_1;
+ break;
+
+ case X_BUTTON_MIDDLE:
+ event->value.keycode = NSFB_KEY_MOUSE_2;
+ break;
+
+ case X_BUTTON_RIGHT:
+ event->value.keycode = NSFB_KEY_MOUSE_3;
+ break;
+
+ case X_BUTTON_WHEELUP:
+ event->value.keycode = NSFB_KEY_MOUSE_4;
+ break;
+
+ case X_BUTTON_WHEELDOWN:
+ event->value.keycode = NSFB_KEY_MOUSE_5;
+ break;
+ }
+ break;
+
+
+ case XCB_KEY_PRESS:
+ ekp = (xcb_key_press_event_t *)e;
+ event->type = NSFB_EVENT_KEY_DOWN;
+ event->value.keycode = xkeysym_to_nsfbkeycode(xcb_key_symbols_get_keysym(xstate->keysymbols, ekp->detail, 0));
+ break;
+
+ case XCB_KEY_RELEASE:
+ ekr = (xcb_key_release_event_t *)e;
+ event->type = NSFB_EVENT_KEY_UP;
+ event->value.keycode = xkeysym_to_nsfbkeycode(xcb_key_symbols_get_keysym(xstate->keysymbols, ekr->detail, 0));
+ break;
+
+ }
+
+ free(e);
+
+ return true;
+}
+#endif
+
+static int wld_claim(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ struct nsfb_cursor_s *cursor = nsfb->cursor;
+
+ if ((cursor != NULL) &&
+ (cursor->plotted == true) &&
+ (nsfb_plot_bbox_intersect(box, &cursor->loc))) {
+ nsfb_cursor_clear(nsfb, cursor);
+ }
+ return 0;
+}
+
+static int
+wld_cursor(nsfb_t *nsfb, struct nsfb_cursor_s *cursor)
+{
+ wldstate_t *wldstate = nsfb->surface_priv;
+ nsfb_bbox_t redraw;
+ nsfb_bbox_t fbarea;
+
+ if ((cursor != NULL) && (cursor->plotted == true)) {
+
+ nsfb_plot_add_rect(&cursor->savloc, &cursor->loc, &redraw);
+
+ /* screen area */
+ fbarea.x0 = 0;
+ fbarea.y0 = 0;
+ fbarea.x1 = nsfb->width;
+ fbarea.y1 = nsfb->height;
+
+ nsfb_plot_clip(&fbarea, &redraw);
+
+ nsfb_cursor_clear(nsfb, cursor);
+
+ nsfb_cursor_plot(nsfb, cursor);
+
+ /* TODO: This is hediously ineficient - should keep the pointer image
+ * as a surface and composite server side
+ */
+ update_and_redraw(wldstate, redraw.x0, redraw.y0, redraw.x1 - redraw.x0, redraw.y1 - redraw.y0);
+
+ }
+ return true;
+
+}
+
+
+static int wld_update(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ wldstate_t *wldstate = nsfb->surface_priv;
+ struct nsfb_cursor_s *cursor = nsfb->cursor;
+
+ if ((cursor != NULL) && (cursor->plotted == false)) {
+ nsfb_cursor_plot(nsfb, cursor);
+ }
+
+ if (wldstate != NULL) {
+ update_and_redraw(wldstate, box->x0, box->y0, box->x1 - box->x0, box->y1 - box->y0);
+ }
+ return 0;
+}
+
+
+const nsfb_surface_rtns_t wld_rtns = {
+ .initialise = wld_initialise,
+ .finalise = wld_finalise,
+ .input = wld_input,
+ .claim = wld_claim,
+ .update = wld_update,
+ .cursor = wld_cursor,
+ .geometry = wld_set_geometry,
+};
+
+NSFB_SURFACE_DEF(wld, NSFB_SURFACE_WL, &wld_rtns)
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * End:
+ */
diff --git a/src/surface/x.c b/src/surface/x.c
index b9c3429..f5ee01b 100644
--- a/src/surface/x.c
+++ b/src/surface/x.c
@@ -79,8 +79,8 @@ typedef struct xstate_s {
xcb_shm_seg_t segment; /* The handle to the image shared memory */
} xstate_t;
-/* X keyboard codepage to nsfb mapping*/
-enum nsfb_key_code_e XCSKeyboardMap[256] = {
+/* X keyboard codepage to nsfb mapping */
+static enum nsfb_key_code_e XCSKeyboardMap[256] = {
NSFB_KEY_UNKNOWN, /* */
NSFB_KEY_UNKNOWN, /* */
NSFB_KEY_UNKNOWN, /* */
diff --git a/test/runtest.sh b/test/runtest.sh
index 2f484e6..9a60b9f 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -2,7 +2,7 @@
TEST_PATH=$1
-TEST_FRONTEND=linux
+TEST_FRONTEND=ram
${TEST_PATH}/test_frontend ${TEST_FRONTEND}
${TEST_PATH}/test_plottest ${TEST_FRONTEND}