Browse Source

Merge pull request #635 from Immediate-Mode-UI/xcb-cairo

Add XCB-Cairo
Rob Loach 1 year ago
parent
commit
a10a830b0e

+ 1 - 15
demo/allegro5/main.c

@@ -41,7 +41,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-#define INCLUDE_OVERVIEW
+/*#define INCLUDE_OVERVIEW */
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL
@@ -114,20 +114,6 @@ int main(void)
 
     ctx = nk_allegro5_init(font, display, WINDOW_WIDTH, WINDOW_HEIGHT);
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     while(1)
     {
         bool get_event;

+ 22 - 1
demo/common/overview.c

@@ -4,7 +4,7 @@ overview(struct nk_context *ctx)
     /* window flags */
     static nk_bool show_menu = nk_true;
     static nk_flags window_flags = NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE|NK_WINDOW_MINIMIZABLE;
-    nk_flags actual_window_flags;
+    nk_flags actual_window_flags = 0;
 
     /* widget flags */
 	static nk_bool disable_widgets = nk_false;
@@ -13,6 +13,13 @@ overview(struct nk_context *ctx)
     static enum nk_style_header_align header_align = NK_HEADER_RIGHT;
     static nk_bool show_app_about = nk_false;
 
+#ifdef INCLUDE_STYLE
+    /* styles */
+    static const char* themes[] = {"Black", "White", "Red", "Blue", "Dark"};
+    static int current_theme = 0;
+#endif
+
+    /* window flags */
     ctx->style.window.header.align = header_align;
 
     actual_window_flags = window_flags;
@@ -121,6 +128,20 @@ overview(struct nk_context *ctx)
             } else show_app_about = nk_false;
         }
 
+#ifdef INCLUDE_STYLE
+        /* style selector */
+        nk_layout_row_dynamic(ctx, 0, 2);
+        {
+            int new_theme;
+            nk_label(ctx, "Style:", NK_TEXT_LEFT);
+            new_theme = nk_combo(ctx, themes, NK_LEN(themes), current_theme, 25, nk_vec2(200, 200));
+            if (new_theme != current_theme) {
+                current_theme = new_theme;
+                set_style(ctx, current_theme);
+            }
+        }
+#endif
+
         /* window flags */
         if (nk_tree_push(ctx, NK_TREE_TAB, "Window", NK_MINIMIZED)) {
             nk_layout_row_dynamic(ctx, 30, 2);

+ 0 - 14
demo/d3d11/main.c

@@ -208,20 +208,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle)*/;}
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 14
demo/d3d12/main.c

@@ -300,20 +300,6 @@ int main(void)
     /* Now we can cleanup all resources consumed by font stashing that are no longer used */
     nk_d3d12_font_stash_cleanup();
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 14
demo/d3d9/main.c

@@ -214,20 +214,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle)*/;}
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 14
demo/gdi/main.c

@@ -113,20 +113,6 @@ int main(void)
     font = nk_gdifont_create("Arial", 14);
     ctx = nk_gdi_init(font, dc, WINDOW_WIDTH, WINDOW_HEIGHT);
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     while (running)
     {
         /* Input */

+ 0 - 14
demo/gdip/main.c

@@ -109,20 +109,6 @@ int main(void)
     font = nk_gdipfont_create("Arial", 12);
     nk_gdip_set_font(font);
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     while (running)
     {
         /* Input */

+ 2 - 14
demo/glfw_opengl2/main.c

@@ -40,7 +40,7 @@
 /* #define INCLUDE_ALL          */
 /* #define INCLUDE_STYLE        */
 /* #define INCLUDE_CALCULATOR   */
-#define INCLUDE_CANVAS
+/* #define INCLUDE_CANVAS       */
 /* #define INCLUDE_FILE_BROWSER */
 /* #define INCLUDE_OVERVIEW     */
 /* #define INCLUDE_NODE_EDITOR  */
@@ -49,6 +49,7 @@
   #define INCLUDE_STYLE
   #define INCLUDE_CALCULATOR
   #define INCLUDE_CANVAS
+  #define INCLUDE_FILE_BROWSER
   #define INCLUDE_OVERVIEW
   #define INCLUDE_NODE_EDITOR
 #endif
@@ -120,19 +121,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/}
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
 
     #ifdef INCLUDE_FILE_BROWSER

+ 1 - 14
demo/glfw_opengl3/main.c

@@ -42,7 +42,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-#define INCLUDE_OVERVIEW
+/*#define INCLUDE_OVERVIEW */
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL
@@ -125,19 +125,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/}
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (!glfwWindowShouldClose(win))
     {

+ 1 - 14
demo/glfw_opengl4/main.c

@@ -42,7 +42,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-#define INCLUDE_OVERVIEW
+/*#define INCLUDE_OVERVIEW */
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL
@@ -125,19 +125,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/}
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     /* Create bindless texture.
      * The index returned is not the opengl resource id.
      * IF you need the GL resource id use: nk_glfw3_get_tex_ogl_id() */

+ 1 - 15
demo/glfw_vulkan/main.c

@@ -35,7 +35,7 @@
  * ===============================================================*/
 /* This are some code examples to provide a small overview of what can be
  * done with this library. To try out an example uncomment the defines */
-#define INCLUDE_ALL
+/*#define INCLUDE_ALL */
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
@@ -2104,20 +2104,6 @@ int main(void) {
         /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/}
 
-#ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for
-     * anything else */
-#ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-#elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-#elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-#elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-#endif
-#endif
-
     img = nk_image_ptr(demo.demo_texture_image_view);
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (!glfwWindowShouldClose(demo.win)) {

+ 0 - 13
demo/rawfb/x11/main.c

@@ -193,19 +193,6 @@ main(void)
     rawfb = nk_rawfb_init(fb, tex_scratch, xw.width, xw.height, xw.width * 4, pl);
     if (!rawfb) running = 0;
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(&rawfb->ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(&rawfb->ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(&rawfb->ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(&rawfb->ctx, THEME_DARK);
-    #endif
-    #endif
-
     while (running) {
         /* Input */
         XEvent evt;

+ 0 - 13
demo/sdl_opengl2/main.c

@@ -116,19 +116,6 @@ main(int argc, char *argv[])
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &roboto->handle)*/;}
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 14
demo/sdl_opengl3/main.c

@@ -126,20 +126,6 @@ int main(int argc, char *argv[])
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &roboto->handle);*/}
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 14
demo/sdl_opengles2/main.c

@@ -209,20 +209,6 @@ int main(int argc, char* argv[])
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &roboto->handle)*/;}
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
 #if defined(__EMSCRIPTEN__)
     #include <emscripten.h>
     emscripten_set_main_loop_arg(MainLoop, (void*)ctx, 0, nk_true);

+ 1 - 13
demo/sdl_renderer/main.c

@@ -36,6 +36,7 @@
 /*#define INCLUDE_ALL */
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_CANVAS */
 /*#define INCLUDE_OVERVIEW */
 /*#define INCLUDE_NODE_EDITOR */
 
@@ -154,19 +155,6 @@ main(int argc, char *argv[])
         nk_style_set_font(ctx, &font->handle);
     }
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 14
demo/sfml_opengl2/main.cpp

@@ -96,20 +96,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     struct nk_colorf bg;
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (win.isOpen())

+ 0 - 14
demo/sfml_opengl3/main.cpp

@@ -102,20 +102,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/
 
-    /* style.c */
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     struct nk_colorf bg;
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (win.isOpen())

+ 0 - 13
demo/x11/main.c

@@ -152,19 +152,6 @@ main(void)
     xw.font = nk_xfont_create(xw.dpy, "fixed");
     ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win, xw.width, xw.height);
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     while (running)
     {
         /* Input */

+ 0 - 13
demo/x11_opengl2/main.c

@@ -256,19 +256,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/}
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 13
demo/x11_opengl3/main.c

@@ -253,19 +253,6 @@ int main(void)
     /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
     /*nk_style_set_font(ctx, &droid->handle);*/}
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
     while (running)
     {

+ 0 - 13
demo/x11_xft/main.c

@@ -156,19 +156,6 @@ main(void)
 #endif
                     xw.width, xw.height);
 
-    #ifdef INCLUDE_STYLE
-    /* ease regression testing during Nuklear release process; not needed for anything else */
-    #ifdef STYLE_WHITE
-    set_style(ctx, THEME_WHITE);
-    #elif defined(STYLE_RED)
-    set_style(ctx, THEME_RED);
-    #elif defined(STYLE_BLUE)
-    set_style(ctx, THEME_BLUE);
-    #elif defined(STYLE_DARK)
-    set_style(ctx, THEME_DARK);
-    #endif
-    #endif
-
     while (running)
     {
         /* Input */

+ 24 - 0
demo/xcb_cairo/Makefile

@@ -0,0 +1,24 @@
+# Target
+BIN = demo
+CFLAGS += -std=c89 -pedantic -O2
+LDFLAGS += -lm
+SRC = ${wildcard *.c}
+OBJ = $(SRC:.c=.o)
+
+# Freetype
+CFLAGS += ${shell pkg-config --cflags freetype2}
+LDFLAGS += ${shell pkg-config --libs freetype2}
+
+# XCB
+CFLAGS += ${shell pkg-config --cflags xcb xcb-util xcb-keysyms}
+LDFLAGS += ${shell pkg-config --libs xcb xcb-util xcb-keysyms}
+
+# Cairo
+CFLAGS += ${shell pkg-config --cflags cairo}
+LDFLAGS += ${shell pkg-config --libs cairo}
+
+# Rules
+$(BIN):
+	@mkdir -p bin
+	rm -f bin/$(BIN) $(OBJS)
+	$(CC) $(SRC) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) ${LDFLAGS}

+ 168 - 0
demo/xcb_cairo/main.c

@@ -0,0 +1,168 @@
+/* nuklear - v1.32.0 - public domain */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#include "../../nuklear.h"
+
+#define NK_XCB_CAIRO_IMPLEMENTATION
+#include "nuklear_xcb.h"
+
+static void die(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fputs("\n", stderr);
+    exit(EXIT_FAILURE);
+}
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+/*#define INCLUDE_CANVAS */
+
+#ifdef INCLUDE_ALL
+  #define INCLUDE_STYLE
+  #define INCLUDE_CALCULATOR
+  #define INCLUDE_OVERVIEW
+  #define INCLUDE_NODE_EDITOR
+  #define INCLUDE_CANVAS
+#endif
+
+#ifdef INCLUDE_STYLE
+  #include "../common/style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+  #include "../common/calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+  #include "../common/overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+  #include "../common/node_editor.c"
+#endif
+#ifdef INCLUDE_CANVAS
+  #include "../common/canvas.c"
+#endif
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+int
+main(void)
+{
+    struct nk_xcb_context *xcb_ctx;
+    struct nk_color background = nk_rgb(0, 0, 0);
+    struct nk_cairo_context *cairo_ctx;
+    struct nk_user_font *font;
+    struct nk_context* ctx;
+    int running = 1;
+    int events;
+
+    xcb_ctx = nk_xcb_init("Nuklear XCB/Cairo", 20, 20, 600, 800);
+    cairo_ctx = nk_cairo_init(&background, NULL, 0, nk_xcb_create_cairo_surface(xcb_ctx));
+    /*cairo_ctx = nk_cairo_init(&background, "../../extra_font/DroidSans.ttf", 0, nk_xcb_create_surface(xcb_ctx));*/
+    font = nk_cairo_default_font(cairo_ctx);
+    ctx = malloc(sizeof(struct nk_context));
+    nk_init_default(ctx, font);
+
+    #ifdef INCLUDE_STYLE
+    set_style(ctx, THEME_BLACK);
+    /*nk_style_push_float(ctx, &ctx->style.window.rounding, 20.0f);*/
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+    #endif
+
+    while (running)
+    {
+        /* Events */
+        events = nk_xcb_handle_event(xcb_ctx, ctx);
+        if (events & NK_XCB_EVENT_STOP) {
+            break;
+        }
+        if (events & NK_XCB_EVENT_PAINT) {
+            nk_cairo_damage(cairo_ctx);
+        }
+        if (events & NK_XCB_EVENT_RESIZED) {
+            nk_xcb_resize_cairo_surface(xcb_ctx, nk_cairo_surface(cairo_ctx));
+        }
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+            nk_layout_row_dynamic(ctx, 25, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+        }
+        nk_end(ctx);
+        if (nk_window_is_hidden(ctx, "Demo")) {
+            break;
+        }
+
+        /* -------------- EXAMPLES ---------------- */
+        #ifdef INCLUDE_CALCULATOR
+        calculator(ctx);
+        #endif
+        #ifdef INCLUDE_OVERVIEW
+        overview(ctx);
+        #endif
+        #ifdef INCLUDE_NODE_EDITOR
+        node_editor(ctx);
+        #endif
+        #ifdef INCLUDE_CANVAS
+        canvas(ctx);
+        #endif
+        /* ----------------------------------------- */
+
+        /* Render */
+        nk_cairo_render(cairo_ctx, ctx);
+        nk_xcb_render(xcb_ctx);
+        nk_clear(ctx);
+    }
+
+    nk_free(ctx);
+    free(ctx);
+    nk_cairo_free(cairo_ctx);
+    nk_xcb_free(xcb_ctx);
+
+    return EXIT_SUCCESS;
+}

+ 836 - 0
demo/xcb_cairo/nuklear_xcb.h

@@ -0,0 +1,836 @@
+/*****************************************************************************
+ *
+ * Nuklear XCB/Cairo Render Backend - v0.0.2
+ * Copyright 2021 Richard Gill
+ * 
+ * Grabbed and adapted from https://github.com/griebd/nuklear_xcb
+ * Copyright 2017 Adriano Grieb
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ *                                API
+ *
+ ****************************************************************************/
+
+#ifndef NK_XCB_CAIRO_H
+#define NK_XCB_CAIRO_H
+
+struct nk_xcb_context;
+struct nk_cairo_context;
+
+/* With Xcb, we work mostly on events, so to do something only when
+ * needed it's good to know what kind of events pulled us from sleep
+ */
+enum nk_xcb_event_type {
+    NK_XCB_EVENT_PAINT      = 0x02,
+    NK_XCB_EVENT_RESIZED    = 0x04,
+    NK_XCB_EVENT_STOP       = 0x08
+};
+
+/* Xcb part: work on windows */
+NK_API struct nk_xcb_context *nk_xcb_init(const char *title, int pos_x, int pos_y, int width, int height);
+NK_API void nk_xcb_free(struct nk_xcb_context *xcb_ctx);
+
+NK_API int nk_xcb_handle_event(struct nk_xcb_context *xcb_ctx, struct nk_context *nk_ctx);
+NK_API void nk_xcb_render(struct nk_xcb_context *xcb_ctx);
+NK_API void nk_xcb_size(struct nk_xcb_context *xcb_ctx, int *width, int *height);
+
+/* TODO: copy/paste */
+
+/* Cairo part: work on painting */
+NK_API struct nk_cairo_context *nk_cairo_init(struct nk_color *bg, const char *font_file, double font_size, void *surface);
+NK_API void nk_cairo_free(struct nk_cairo_context *cairo_ctx);
+
+NK_API struct nk_user_font *nk_cairo_default_font(struct nk_cairo_context *cairo_ctx);
+NK_API void nk_cairo_damage(struct nk_cairo_context *cairo_ctx);
+NK_API int nk_cairo_render(struct nk_cairo_context *cairo_ctx, struct nk_context *ctx);
+
+/* Bridge between xcb and cairo (so it's possible to use them like legos) */
+NK_API void *nk_xcb_create_cairo_surface(struct nk_xcb_context *xcb_ctx);
+NK_API void nk_xcb_resize_cairo_surface(struct nk_xcb_context *xcb_ctx, void *surface);
+
+
+#endif /* NK_XCB_CAIRO_H */
+
+/*****************************************************************************
+ *
+ *                           IMPLEMENTATION
+ *
+ ****************************************************************************/
+
+#ifdef NK_XCB_CAIRO_IMPLEMENTATION
+
+#include <xcb/xcb.h>
+#include <xcb/xcb_util.h>
+#include <xcb/xcb_keysyms.h>
+#include <X11/keysym.h>
+#include <cairo/cairo-xcb.h>
+#include <cairo/cairo-ft.h>
+
+#if defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600 || \
+    defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L
+#include <time.h>
+#include <errno.h>
+#ifndef NK_XCB_FPS
+#define NK_XCB_FPS 30
+#endif /* NK_XCB_FPS */
+#define NK_XCB_NSEC 1000000000
+#define NK_XCB_MIN_FRAME_TIME (NK_XCB_NSEC / NK_XCB_FPS)
+#endif
+
+#include <math.h>
+#ifdef __USE_GNU
+#define NK_XCB_PI M_PIl
+#elif defined __USE_BSD || defined __USE_XOPEN
+#define NK_XCB_PI M_PI
+#else
+#define NK_XCB_PI acos(-1.0)
+#endif
+
+#define NK_XCB_TO_CAIRO(x) ((double) x / 255.0)
+#define NK_XCB_DEG_TO_RAD(x) ((double) x * NK_XCB_PI / 180.0)
+
+struct nk_cairo_context {
+    cairo_surface_t *surface;
+    cairo_t *cr;
+
+    struct nk_user_font *font;
+    struct nk_color *bg;
+
+    void *last_buffer;
+    nk_size buffer_size;
+    int repaint;
+};
+
+struct nk_xcb_context {
+    xcb_connection_t *conn;
+    int screennum;
+    xcb_window_t window;
+    xcb_key_symbols_t *key_symbols;
+#ifdef NK_XCB_MIN_FRAME_TIME
+    unsigned long last_render;
+#endif /* NK_XCB_MIN_FRAME_TIME */
+    int events;
+    xcb_intern_atom_reply_t* del_atom;
+    int width, height;
+};
+
+NK_API struct nk_xcb_context *nk_xcb_init(const char *title, int pos_x, int pos_y, int width, int height)
+{
+    int screenNum;
+    xcb_connection_t *conn;
+    xcb_screen_t *screen;
+    xcb_window_t window;
+    uint32_t values[1];
+    struct nk_xcb_context *xcb_ctx;
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply, *del_atom;
+
+    conn = xcb_connect(NULL, &screenNum);
+    if (xcb_connection_has_error(conn)) {
+        xcb_disconnect(conn);
+        return NULL;
+    }
+    screen = xcb_aux_get_screen(conn, screenNum);
+
+    window = xcb_generate_id(conn);
+    values[0] = 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
+        | XCB_EVENT_MASK_BUTTON_1_MOTION
+        | XCB_EVENT_MASK_BUTTON_2_MOTION
+        | XCB_EVENT_MASK_BUTTON_3_MOTION
+        | XCB_EVENT_MASK_BUTTON_4_MOTION
+        | XCB_EVENT_MASK_BUTTON_5_MOTION
+        | XCB_EVENT_MASK_BUTTON_MOTION
+        | XCB_EVENT_MASK_KEYMAP_STATE
+        | XCB_EVENT_MASK_EXPOSURE
+        | XCB_EVENT_MASK_STRUCTURE_NOTIFY
+        ;
+    xcb_create_window(conn, XCB_COPY_FROM_PARENT, window, screen->root,
+            pos_x, pos_y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+            XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
+
+    cookie = xcb_intern_atom(conn, 1, 12, "WM_PROTOCOLS");
+    reply = xcb_intern_atom_reply(conn, cookie, 0);
+    cookie = xcb_intern_atom(conn, 0, 16, "WM_DELETE_WINDOW");
+    del_atom = xcb_intern_atom_reply(conn, cookie, 0);
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window, reply->atom, 4, 32, 1, &del_atom->atom);
+    free(reply);
+
+    xcb_map_window(conn, window);
+    xcb_flush(conn);
+
+    xcb_ctx = malloc(sizeof (struct nk_xcb_context));
+    xcb_ctx->conn = conn;
+    xcb_ctx->screennum = screenNum;
+    xcb_ctx->window = window;
+    xcb_ctx->key_symbols = xcb_key_symbols_alloc(xcb_ctx->conn);
+    xcb_ctx->del_atom = del_atom;
+    xcb_ctx->width = width;
+    xcb_ctx->height = height;
+
+    return xcb_ctx;
+}
+
+NK_API void nk_xcb_free(struct nk_xcb_context *xcb_ctx)
+{
+    free(xcb_ctx->del_atom);
+    xcb_key_symbols_free(xcb_ctx->key_symbols);
+    xcb_disconnect(xcb_ctx->conn);
+    free(xcb_ctx);
+}
+
+NK_API int nk_xcb_handle_event(struct nk_xcb_context *xcb_ctx, struct nk_context *nk_ctx)
+{
+    int events = 0;
+    xcb_generic_event_t *event;
+
+#ifdef NK_XCB_MIN_FRAME_TIME
+    struct timespec tp;
+
+    clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);
+    xcb_ctx->last_render = tp.tv_sec * NK_XCB_NSEC + tp.tv_nsec;
+#endif /* NK_XCB_MIN_FRAME_TIME */
+
+    event = xcb_wait_for_event(xcb_ctx->conn);
+
+    nk_input_begin(nk_ctx);
+    do {
+        switch (XCB_EVENT_RESPONSE_TYPE(event)) {
+        case XCB_KEY_PRESS:
+        case XCB_KEY_RELEASE:
+            {
+                int press = (XCB_EVENT_RESPONSE_TYPE(event)) == XCB_KEY_PRESS;
+                xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event;
+                xcb_keysym_t sym = xcb_key_symbols_get_keysym(xcb_ctx->key_symbols, kp->detail, kp->state);
+                switch (sym) {
+                case XK_Shift_L:
+                case XK_Shift_R:
+                    nk_input_key(nk_ctx, NK_KEY_SHIFT, press);
+                    break;
+                case XK_Control_L:
+                case XK_Control_R:
+                    nk_input_key(nk_ctx, NK_KEY_CTRL, press);
+                    break;
+                case XK_Delete:
+                    nk_input_key(nk_ctx, NK_KEY_DEL, press);
+                    break;
+                case XK_Return:
+                    nk_input_key(nk_ctx, NK_KEY_ENTER, press);
+                    break;
+                case XK_Tab:
+                    nk_input_key(nk_ctx, NK_KEY_TAB, press);
+                    break;
+                case XK_BackSpace:
+                    nk_input_key(nk_ctx, NK_KEY_BACKSPACE, press);
+                    break;
+                /* case NK_KEY_COPY */
+                /* case NK_KEY_CUT */
+                /* case NK_KEY_PASTE */
+                case XK_Up:
+                    nk_input_key(nk_ctx, NK_KEY_UP, press);
+                    break;
+                case XK_Down:
+                    nk_input_key(nk_ctx, NK_KEY_DOWN, press);
+                    break;
+                case XK_Left:
+                    nk_input_key(nk_ctx, NK_KEY_LEFT, press);
+                    break;
+                case XK_Right:
+                    nk_input_key(nk_ctx, NK_KEY_RIGHT, press);
+                    break;
+                /* NK_KEY_TEXT_INSERT_MODE, */
+                /* NK_KEY_TEXT_REPLACE_MODE, */
+                case XK_Escape:
+                    nk_input_key(nk_ctx, NK_KEY_TEXT_RESET_MODE, press);
+                    break;
+                /* NK_KEY_TEXT_LINE_START, */
+                /* NK_KEY_TEXT_LINE_END, */
+                case XK_Home:
+                    {
+                        nk_input_key(nk_ctx, NK_KEY_TEXT_START, press);
+                        nk_input_key(nk_ctx, NK_KEY_SCROLL_START, press);
+                    }
+                    break;
+                case XK_End:
+                    {
+                        nk_input_key(nk_ctx, NK_KEY_TEXT_END, press);
+                        nk_input_key(nk_ctx, NK_KEY_SCROLL_END, press);
+                    }
+                    break;
+                /* NK_KEY_TEXT_UNDO, */
+                /* NK_KEY_TEXT_REDO, */
+                /* NK_KEY_TEXT_SELECT_ALL, */
+                /* NK_KEY_TEXT_WORD_LEFT, */
+                /* NK_KEY_TEXT_WORD_RIGHT, */
+                case XK_Page_Down:
+                    nk_input_key(nk_ctx, NK_KEY_SCROLL_DOWN, press);
+                    break;
+                case XK_Page_Up:
+                    nk_input_key(nk_ctx, NK_KEY_SCROLL_UP, press);
+                    break;
+                default:
+                    if (press &&
+                            !xcb_is_keypad_key(sym) &&
+                            !xcb_is_private_keypad_key(sym) &&
+                            !xcb_is_cursor_key(sym) &&
+                            !xcb_is_pf_key(sym) &&
+                            !xcb_is_function_key(sym) &&
+                            !xcb_is_misc_function_key(sym) &&
+                            !xcb_is_modifier_key(sym)
+                            ) {
+                        nk_input_char(nk_ctx, sym);
+                    }
+                    else {
+                        printf("state: %x code: %x sum: %x\n", kp->state, kp->detail, sym);
+                    }
+                    break;
+                }
+            }
+            break;
+        case XCB_BUTTON_PRESS:
+        case XCB_BUTTON_RELEASE:
+            {
+                int press = (XCB_EVENT_RESPONSE_TYPE(event)) == XCB_BUTTON_PRESS;
+                xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event;
+                switch (bp->detail) {
+                case XCB_BUTTON_INDEX_1:
+                    nk_input_button(nk_ctx, NK_BUTTON_LEFT, bp->event_x, bp->event_y, press);
+                    break;
+                case XCB_BUTTON_INDEX_2:
+                    nk_input_button(nk_ctx, NK_BUTTON_MIDDLE, bp->event_x, bp->event_y, press);
+                    break;
+                case XCB_BUTTON_INDEX_3:
+                    nk_input_button(nk_ctx, NK_BUTTON_RIGHT, bp->event_x, bp->event_y, press);
+                    break;
+                case XCB_BUTTON_INDEX_4:
+                    nk_input_scroll(nk_ctx, nk_vec2(0, 1.0f));
+                    break;
+                case XCB_BUTTON_INDEX_5:
+                    nk_input_scroll(nk_ctx, nk_vec2(0, -1.0f));
+                    break;
+                default: break;
+                }
+            }
+            break;
+        case XCB_MOTION_NOTIFY:
+            {
+                xcb_motion_notify_event_t *mn = (xcb_motion_notify_event_t *)event;
+                nk_input_motion(nk_ctx, mn->event_x, mn->event_y);
+            }
+            break;
+        case XCB_SELECTION_CLEAR:
+            {
+                printf("Unhandled event: %s\n", xcb_event_get_label(event->response_type));
+            }
+            break;
+        case XCB_SELECTION_REQUEST:
+            {
+                printf("Unhandled event: %s\n", xcb_event_get_label(event->response_type));
+            }
+            break;
+        case XCB_SELECTION_NOTIFY:
+            {
+                printf("Unhandled event: %s\n", xcb_event_get_label(event->response_type));
+            }
+            break;
+        case XCB_CONFIGURE_NOTIFY:
+            {
+                xcb_configure_notify_event_t *cn = (xcb_configure_notify_event_t *)event;
+                xcb_ctx->width = cn->width;
+                xcb_ctx->height = cn->height;
+                events |= NK_XCB_EVENT_RESIZED;
+            }
+            break;
+        case XCB_KEYMAP_NOTIFY:
+            xcb_refresh_keyboard_mapping(xcb_ctx->key_symbols, (xcb_mapping_notify_event_t *)event);
+            break;
+        case XCB_EXPOSE:
+        case XCB_REPARENT_NOTIFY:
+        case XCB_MAP_NOTIFY:
+            events |= NK_XCB_EVENT_PAINT;
+            break;
+        case XCB_CLIENT_MESSAGE:
+            {
+                xcb_client_message_event_t *cm = (xcb_client_message_event_t *)event;
+                if (cm->data.data32[0] == xcb_ctx->del_atom->atom)
+                {
+                    return NK_XCB_EVENT_STOP;
+                }
+            }
+            break;
+        default:
+            printf ("Unhandled event: %s\n", xcb_event_get_label(event->response_type));
+            break;
+        }
+        free(event);
+    }
+    while ((event = xcb_poll_for_event(xcb_ctx->conn)));
+    nk_input_end(nk_ctx);
+
+    return events;
+}
+
+NK_API void nk_xcb_render(struct nk_xcb_context *xcb_ctx)
+{
+    xcb_flush (xcb_ctx->conn);
+
+#ifdef NK_XCB_MIN_FRAME_TIME
+    {
+        struct timespec tp;
+        unsigned long spent;
+        clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);
+        spent = tp.tv_sec * NK_XCB_NSEC + tp.tv_nsec - xcb_ctx->last_render;
+        if (NK_XCB_MIN_FRAME_TIME > spent) {
+            tp.tv_sec = 0;
+            tp.tv_nsec = NK_XCB_MIN_FRAME_TIME - spent;
+            while (clock_nanosleep(CLOCK_MONOTONIC, 0, &tp, &tp) == EINTR);
+        }
+    }
+#endif /* NK_XCB_MIN_FRAME_TIME */
+}
+
+NK_API void nk_xcb_size(struct nk_xcb_context *xcb_ctx, int *width, int *height)
+{
+    *width = xcb_ctx->width;
+    *height = xcb_ctx->height;
+}
+
+NK_API void *nk_xcb_create_cairo_surface(struct nk_xcb_context *xcb_ctx)
+{
+    xcb_screen_t *screen;
+    xcb_visualtype_t *visual;
+
+    screen = xcb_aux_get_screen(xcb_ctx->conn, xcb_ctx->screennum);
+    visual = xcb_aux_get_visualtype(xcb_ctx->conn, xcb_ctx->screennum, screen->root_visual);
+    return cairo_xcb_surface_create(xcb_ctx->conn, xcb_ctx->window, visual, xcb_ctx->width, xcb_ctx->height);
+}
+
+NK_API void nk_xcb_resize_cairo_surface(struct nk_xcb_context *xcb_ctx, void *surface)
+{
+    cairo_xcb_surface_set_size((cairo_surface_t *)surface, xcb_ctx->width, xcb_ctx->height);
+}
+
+
+
+#define NK_TO_CAIRO(x) ((double) x / 255.0)
+
+
+NK_INTERN float nk_cairo_text_width(nk_handle handle, float height __attribute__ ((__unused__)), const char *text, int len)
+{
+    cairo_scaled_font_t *font = handle.ptr;
+    cairo_glyph_t *glyphs = NULL;
+    int num_glyphs;
+    cairo_text_extents_t extents;
+
+    cairo_scaled_font_text_to_glyphs(font, 0, 0, text, len, &glyphs, &num_glyphs, NULL, NULL, NULL);
+    cairo_scaled_font_glyph_extents(font, glyphs, num_glyphs, &extents);
+    cairo_glyph_free(glyphs);
+
+    return extents.x_advance;
+}
+
+NK_API struct nk_cairo_context *nk_cairo_init(struct nk_color *bg, const char *font_file, double font_size, void *surf)
+{
+    cairo_surface_t *surface = surf;
+    struct nk_cairo_context *cairo_ctx;
+    cairo_t *cr;
+    cairo_font_extents_t extents;
+    cairo_scaled_font_t *default_font;
+    struct nk_user_font *font;
+
+    cr = cairo_create(surface);
+    font = malloc(sizeof (struct nk_user_font));
+    if (font_file != NULL) {
+        FT_Library library;
+        FT_Face face;
+        cairo_font_face_t *font_face;
+        static const cairo_user_data_key_t key;
+
+        FT_Init_FreeType(&library);
+        FT_New_Face(library, font_file, 0, &face);
+        font_face = cairo_ft_font_face_create_for_ft_face(face, 0);
+        cairo_font_face_set_user_data(font_face, &key, face, (cairo_destroy_func_t)FT_Done_Face);
+        cairo_set_font_face(cr, font_face);
+    }
+    if (font_size < 0.01) {
+        font_size = 11.0;
+    }
+    cairo_set_font_size(cr, font_size);
+    default_font = cairo_get_scaled_font(cr);
+    cairo_scaled_font_extents(default_font, &extents);
+    font->userdata.ptr = default_font;
+    font->height = extents.height;
+    font->width = nk_cairo_text_width;
+
+    cairo_ctx = malloc(sizeof(struct nk_cairo_context));
+    cairo_ctx->surface = (cairo_surface_t *)surface;
+    cairo_ctx->cr = cr;
+    cairo_ctx->font = font;
+    cairo_ctx->bg = bg;
+    cairo_ctx->last_buffer = NULL;
+    cairo_ctx->buffer_size = 0;
+    cairo_ctx->repaint = nk_false;
+
+    return cairo_ctx;
+}
+
+NK_API cairo_surface_t *nk_cairo_surface(struct nk_cairo_context *cairo_ctx)
+{
+    return cairo_ctx->surface;
+}
+
+NK_API struct nk_user_font *nk_cairo_default_font(struct nk_cairo_context *cairo_ctx)
+{
+    return cairo_ctx->font;
+}
+
+NK_API void nk_cairo_free(struct nk_cairo_context *cairo_ctx)
+{
+    free (cairo_ctx->last_buffer);
+    cairo_destroy(cairo_ctx->cr);
+    cairo_surface_destroy(cairo_ctx->surface);
+    free(cairo_ctx->font);
+    free(cairo_ctx);
+}
+
+NK_API void nk_cairo_damage(struct nk_cairo_context *cairo_ctx)
+{
+    cairo_ctx->repaint = nk_true;
+}
+
+NK_API int nk_cairo_render(struct nk_cairo_context *cairo_ctx, struct nk_context *nk_ctx)
+{
+    cairo_t *cr;
+    const struct nk_command *cmd = NULL;
+    void *cmds = nk_buffer_memory(&nk_ctx->memory);
+
+    if (cairo_ctx->buffer_size != nk_ctx->memory.allocated) {
+        cairo_ctx->buffer_size = nk_ctx->memory.allocated;
+        cairo_ctx->last_buffer = realloc(cairo_ctx->last_buffer, cairo_ctx->buffer_size);
+        memcpy(cairo_ctx->last_buffer, cmds, cairo_ctx->buffer_size);
+    }
+    else if (!memcmp(cmds, cairo_ctx->last_buffer, cairo_ctx->buffer_size)) {
+        if (!cairo_ctx->repaint) {
+            return nk_false;
+        }
+        cairo_ctx->repaint = nk_false;
+    }
+    else {
+        memcpy(cairo_ctx->last_buffer, cmds, cairo_ctx->buffer_size);
+    }
+
+    cr = cairo_ctx->cr;
+    cairo_push_group(cr);
+
+    cairo_set_source_rgb(cr, NK_TO_CAIRO(cairo_ctx->bg->r), NK_TO_CAIRO(cairo_ctx->bg->g), NK_TO_CAIRO(cairo_ctx->bg->b));
+    cairo_paint(cr);
+
+    nk_foreach(cmd, nk_ctx) {
+        switch (cmd->type) {
+        case NK_COMMAND_NOP:
+            break;
+        case NK_COMMAND_SCISSOR:
+            {
+                const struct nk_command_scissor *s = (const struct nk_command_scissor *)cmd;
+                cairo_reset_clip(cr);
+                if (s->x >= 0) {
+                    cairo_rectangle(cr, s->x - 1, s->y - 1, s->w + 2, s->h + 2);
+                    cairo_clip(cr);
+                }
+            }
+            break;
+        case NK_COMMAND_LINE:
+            {
+                const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(l->color.r), NK_TO_CAIRO(l->color.g), NK_TO_CAIRO(l->color.b), NK_TO_CAIRO(l->color.a));
+                cairo_set_line_width(cr, l->line_thickness);
+                cairo_move_to(cr, l->begin.x, l->begin.y);
+                cairo_line_to(cr, l->end.x, l->end.y);
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_CURVE:
+            {
+                const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(q->color.r), NK_TO_CAIRO(q->color.g), NK_TO_CAIRO(q->color.b), NK_TO_CAIRO(q->color.a));
+                cairo_set_line_width(cr, q->line_thickness);
+                cairo_move_to(cr, q->begin.x, q->begin.y);
+                cairo_curve_to(cr, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, q->ctrl[1].y, q->end.x, q->end.y);
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_RECT:
+            {
+                const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(r->color.r), NK_TO_CAIRO(r->color.g), NK_TO_CAIRO(r->color.b), NK_TO_CAIRO(r->color.a));
+                cairo_set_line_width(cr, r->line_thickness);
+                if (r->rounding == 0) {
+                    cairo_rectangle(cr, r->x, r->y, r->w, r->h);
+                }
+                else {
+                    int xl = r->x + r->w - r->rounding;
+                    int xr = r->x + r->rounding;
+                    int yl = r->y + r->h - r->rounding;
+                    int yr = r->y + r->rounding;
+                    cairo_new_sub_path(cr);
+                    cairo_arc(cr, xl, yr, r->rounding, NK_XCB_DEG_TO_RAD(-90), NK_XCB_DEG_TO_RAD(0));
+                    cairo_arc(cr, xl, yl, r->rounding, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(90));
+                    cairo_arc(cr, xr, yl, r->rounding, NK_XCB_DEG_TO_RAD(90), NK_XCB_DEG_TO_RAD(180));
+                    cairo_arc(cr, xr, yr, r->rounding, NK_XCB_DEG_TO_RAD(180), NK_XCB_DEG_TO_RAD(270));
+                    cairo_close_path(cr);
+                }
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_RECT_FILLED:
+            {
+                const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(r->color.r), NK_TO_CAIRO(r->color.g), NK_TO_CAIRO(r->color.b), NK_TO_CAIRO(r->color.a));
+                if (r->rounding == 0) {
+                    cairo_rectangle(cr, r->x, r->y, r->w, r->h);
+                } else {
+                    int xl = r->x + r->w - r->rounding;
+                    int xr = r->x + r->rounding;
+                    int yl = r->y + r->h - r->rounding;
+                    int yr = r->y + r->rounding;
+                    cairo_new_sub_path(cr);
+                    cairo_arc(cr, xl, yr, r->rounding, NK_XCB_DEG_TO_RAD(-90), NK_XCB_DEG_TO_RAD(0));
+                    cairo_arc(cr, xl, yl, r->rounding, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(90));
+                    cairo_arc(cr, xr, yl, r->rounding, NK_XCB_DEG_TO_RAD(90), NK_XCB_DEG_TO_RAD(180));
+                    cairo_arc(cr, xr, yr, r->rounding, NK_XCB_DEG_TO_RAD(180), NK_XCB_DEG_TO_RAD(270));
+                    cairo_close_path(cr);
+                }
+                cairo_fill(cr);
+            }
+            break;
+        case NK_COMMAND_RECT_MULTI_COLOR:
+            {
+                /* from https://github.com/taiwins/twidgets/blob/master/src/nk_wl_cairo.c */
+                const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color *)cmd;
+                cairo_pattern_t *pat = cairo_pattern_create_mesh();
+                if (pat) {
+                    cairo_mesh_pattern_begin_patch(pat);
+                    cairo_mesh_pattern_move_to(pat, r->x, r->y);
+                    cairo_mesh_pattern_line_to(pat, r->x, r->y + r->h);
+                    cairo_mesh_pattern_line_to(pat, r->x + r->w, r->y + r->h);
+                    cairo_mesh_pattern_line_to(pat, r->x + r->w, r->y);
+                    cairo_mesh_pattern_set_corner_color_rgba(pat, 0, NK_TO_CAIRO(r->left.r), NK_TO_CAIRO(r->left.g), NK_TO_CAIRO(r->left.b), NK_TO_CAIRO(r->left.a));
+                    cairo_mesh_pattern_set_corner_color_rgba(pat, 1, NK_TO_CAIRO(r->bottom.r), NK_TO_CAIRO(r->bottom.g), NK_TO_CAIRO(r->bottom.b), NK_TO_CAIRO(r->bottom.a));
+                    cairo_mesh_pattern_set_corner_color_rgba(pat, 2, NK_TO_CAIRO(r->right.r), NK_TO_CAIRO(r->right.g), NK_TO_CAIRO(r->right.b), NK_TO_CAIRO(r->right.a));
+                    cairo_mesh_pattern_set_corner_color_rgba(pat, 3, NK_TO_CAIRO(r->top.r), NK_TO_CAIRO(r->top.g), NK_TO_CAIRO(r->top.b), NK_TO_CAIRO(r->top.a));
+                    cairo_mesh_pattern_end_patch(pat);
+
+                    cairo_rectangle(cr, r->x, r->y, r->w, r->h);
+                    cairo_set_source(cr, pat);
+                    cairo_fill(cr);
+                    cairo_pattern_destroy(pat);
+                }
+            }
+            break;
+        case NK_COMMAND_CIRCLE:
+            {
+                const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(c->color.r), NK_TO_CAIRO(c->color.g), NK_TO_CAIRO(c->color.b), NK_TO_CAIRO(c->color.a));
+                cairo_set_line_width(cr, c->line_thickness);
+                cairo_save(cr);
+                cairo_translate(cr, c->x + c->w / 2.0, c->y + c->h / 2.0);
+                cairo_scale(cr, c->w / 2.0, c->h / 2.0);
+                cairo_arc(cr, 0, 0, 1, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(360));
+                cairo_restore(cr);
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_CIRCLE_FILLED:
+            {
+                const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(c->color.r), NK_TO_CAIRO(c->color.g), NK_TO_CAIRO(c->color.b), NK_TO_CAIRO(c->color.a));
+                cairo_save(cr);
+                cairo_translate(cr, c->x + c->w / 2.0, c->y + c->h / 2.0);
+                cairo_scale(cr, c->w / 2.0, c->h / 2.0);
+                cairo_arc(cr, 0, 0, 1, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(360));
+                cairo_restore(cr);
+                cairo_fill(cr);
+            }
+            break;
+        case NK_COMMAND_ARC:
+            {
+                const struct nk_command_arc *a = (const struct nk_command_arc*) cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(a->color.r), NK_TO_CAIRO(a->color.g), NK_TO_CAIRO(a->color.b), NK_TO_CAIRO(a->color.a));
+                cairo_set_line_width(cr, a->line_thickness);
+                cairo_arc(cr, a->cx, a->cy, a->r, NK_XCB_DEG_TO_RAD(a->a[0]), NK_XCB_DEG_TO_RAD(a->a[1]));
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_ARC_FILLED:
+            {
+                const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled*)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(a->color.r), NK_TO_CAIRO(a->color.g), NK_TO_CAIRO(a->color.b), NK_TO_CAIRO(a->color.a));
+                cairo_arc(cr, a->cx, a->cy, a->r, NK_XCB_DEG_TO_RAD(a->a[0]), NK_XCB_DEG_TO_RAD(a->a[1]));
+                cairo_fill(cr);
+            }
+            break;
+        case NK_COMMAND_TRIANGLE:
+            {
+                const struct nk_command_triangle *t = (const struct nk_command_triangle *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(t->color.r), NK_TO_CAIRO(t->color.g), NK_TO_CAIRO(t->color.b), NK_TO_CAIRO(t->color.a));
+                cairo_set_line_width(cr, t->line_thickness);
+                cairo_move_to(cr, t->a.x, t->a.y);
+                cairo_line_to(cr, t->b.x, t->b.y);
+                cairo_line_to(cr, t->c.x, t->c.y);
+                cairo_close_path(cr);
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_TRIANGLE_FILLED:
+            {
+                const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(t->color.r), NK_TO_CAIRO(t->color.g), NK_TO_CAIRO(t->color.b), NK_TO_CAIRO(t->color.a));
+                cairo_move_to(cr, t->a.x, t->a.y);
+                cairo_line_to(cr, t->b.x, t->b.y);
+                cairo_line_to(cr, t->c.x, t->c.y);
+                cairo_close_path(cr);
+                cairo_fill(cr);
+            }
+            break;
+        case NK_COMMAND_POLYGON:
+            {
+                int i;
+                const struct nk_command_polygon *p = (const struct nk_command_polygon *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(p->color.r), NK_TO_CAIRO(p->color.g), NK_TO_CAIRO(p->color.b), NK_TO_CAIRO(p->color.a));
+                cairo_set_line_width(cr, p->line_thickness);
+                cairo_move_to(cr, p->points[0].x, p->points[0].y);
+                for (i = 1; i < p->point_count; ++i) {
+                    cairo_line_to(cr, p->points[i].x, p->points[i].y);
+                }
+                cairo_close_path(cr);
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_POLYGON_FILLED:
+            {
+                int i;
+                const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+                cairo_set_source_rgba (cr, NK_TO_CAIRO(p->color.r), NK_TO_CAIRO(p->color.g), NK_TO_CAIRO(p->color.b), NK_TO_CAIRO(p->color.a));
+                cairo_move_to(cr, p->points[0].x, p->points[0].y);
+                for (i = 1; i < p->point_count; ++i) {
+                    cairo_line_to(cr, p->points[i].x, p->points[i].y);
+                }
+                cairo_close_path(cr);
+                cairo_fill(cr);
+            }
+            break;
+        case NK_COMMAND_POLYLINE:
+            {
+                int i;
+                const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(p->color.r), NK_TO_CAIRO(p->color.g), NK_TO_CAIRO(p->color.b), NK_TO_CAIRO(p->color.a));
+                cairo_set_line_width(cr, p->line_thickness);
+                cairo_move_to(cr, p->points[0].x, p->points[0].y);
+                for (i = 1; i < p->point_count; ++i) {
+                    cairo_line_to(cr, p->points[i].x, p->points[i].y);
+                }
+                cairo_stroke(cr);
+            }
+            break;
+        case NK_COMMAND_TEXT:
+            {
+                const struct nk_command_text *t = (const struct nk_command_text *)cmd;
+                cairo_glyph_t *glyphs = NULL;
+                int num_glyphs;
+                cairo_text_cluster_t *clusters = NULL;
+                int num_clusters;
+                cairo_text_cluster_flags_t cluster_flags;
+                cairo_font_extents_t extents;
+
+                cairo_set_source_rgba(cr, NK_TO_CAIRO(t->foreground.r), NK_TO_CAIRO(t->foreground.g), NK_TO_CAIRO(t->foreground.b), NK_TO_CAIRO(t->foreground.a));
+                cairo_scaled_font_extents(t->font->userdata.ptr, &extents);
+                cairo_scaled_font_text_to_glyphs(t->font->userdata.ptr,
+                        t->x, t->y + extents.ascent, t->string, t->length,
+                        &glyphs, &num_glyphs, &clusters, &num_clusters,
+                        &cluster_flags);
+                cairo_show_text_glyphs(cr, t->string, t->length, glyphs,
+                        num_glyphs, clusters, num_clusters,
+                        cluster_flags);
+                cairo_glyph_free(glyphs);
+                cairo_text_cluster_free(clusters);
+            }
+            break;
+        case NK_COMMAND_IMAGE:
+            {
+                /* from https://github.com/taiwins/twidgets/blob/master/src/nk_wl_cairo.c */
+                const struct nk_command_image *im = (const struct nk_command_image *)cmd;
+                cairo_surface_t *img_surf;
+                double sw = (double)im->w / (double)im->img.region[2];
+                double sh = (double)im->h / (double)im->img.region[3];
+                cairo_format_t format = CAIRO_FORMAT_ARGB32;
+                int stride = cairo_format_stride_for_width(format, im->img.w);
+
+                if (!im->img.handle.ptr) return;
+                img_surf = cairo_image_surface_create_for_data(im->img.handle.ptr, format, im->img.w, im->img.h, stride);
+                if (!img_surf) return;
+                cairo_save(cr);
+
+                cairo_rectangle(cr, im->x, im->y, im->w, im->h);
+                /* scale here, if after source set, the scale would not apply to source
+                 * surface
+                 */
+                cairo_scale(cr, sw, sh);
+                /* the coordinates system in cairo is not intuitive, scale, translate,
+                 * are applied to source. Refer to
+                 * "https://www.cairographics.org/FAQ/#paint_from_a_surface" for details
+                 * 
+                 * if you set source_origin to (0,0), it would be like source origin
+                 * aligned to dest origin, then if you draw a rectangle on (x, y, w, h).
+                 * it would clip out the (x, y, w, h) of the source on you dest as well.
+                 */
+                cairo_set_source_surface(cr, img_surf, im->x/sw - im->img.region[0], im->y/sh - im->img.region[1]);
+                cairo_fill(cr);
+
+                cairo_restore(cr);
+                cairo_surface_destroy(img_surf);
+            }
+            break;
+        case NK_COMMAND_CUSTOM:
+            {
+	            const struct nk_command_custom *cu = (const struct nk_command_custom *)cmd;
+                if (cu->callback) {
+                    cu->callback(cr, cu->x, cu->y, cu->w, cu->h, cu->callback_data);
+                }
+            }
+        default:
+            break;
+        }
+    }
+
+    cairo_pop_group_to_source(cr);
+    cairo_paint(cr);
+    cairo_surface_flush(cairo_ctx->surface);
+
+    return nk_true;
+}
+
+#endif /* NK_XCB_CAIRO_IMPLEMENTATION */