master hovercats/oakiss / pkg / dmenu / patch / 0001-Port-to-wayland-using-wld-and-swc-panels.patch
   1From d186aa8891ca777615b8138416c95565c05e0a09 Mon Sep 17 00:00:00 2001
   2From: Michael Forney <mforney@mforney.org>
   3Date: Thu, 27 Oct 2016 21:04:23 -0700
   4Subject: [PATCH] Port to wayland using wld and swc panels
   5
   6---
   7 Makefile  |  16 +-
   8 config.mk |  20 +-
   9 dmenu.c   | 566 ++++++++++++++++++++++++++++--------------------------
  10 drw.c     | 130 ++++++-------
  11 drw.h     |  26 ++-
  12 5 files changed, 381 insertions(+), 377 deletions(-)
  13
  14diff --git a/Makefile b/Makefile
  15index a03a95c..4046899 100644
  16--- a/Makefile
  17+++ b/Makefile
  18@@ -3,7 +3,7 @@
  19 
  20 include config.mk
  21 
  22-SRC = drw.c dmenu.c stest.c util.c
  23+SRC = drw.c dmenu.c stest.c panel-protocol.c util.c
  24 OBJ = $(SRC:.c=.o)
  25 
  26 all: options dmenu stest
  27@@ -20,10 +20,18 @@ options:
  28 config.h:
  29 	cp config.def.h $@
  30 
  31-$(OBJ): arg.h config.h config.mk drw.h
  32+swc-protocol.c: $(SWCPROTO)
  33+	@echo GEN $@
  34+	@wayland-scanner code < $< > $@
  35 
  36-dmenu: dmenu.o drw.o util.o
  37-	$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)
  38+swc-client-protocol.h: $(SWCPROTO)
  39+	@echo GEN $@
  40+	@wayland-scanner client-header < $< > $@
  41+
  42+$(OBJ): arg.h config.h config.mk drw.h swc-client-protocol.h
  43+
  44+dmenu: dmenu.o drw.o swc-protocol.o util.o
  45+	$(CC) -o $@ dmenu.o drw.o swc-protocol.o util.o $(LDFLAGS)
  46 
  47 stest: stest.o
  48 	$(CC) -o $@ stest.o $(LDFLAGS)
  49diff --git a/config.mk b/config.mk
  50index 0929b4a..7e747ff 100644
  51--- a/config.mk
  52+++ b/config.mk
  53@@ -5,25 +5,15 @@ VERSION = 4.9
  54 PREFIX = /usr/local
  55 MANPREFIX = $(PREFIX)/share/man
  56 
  57-X11INC = /usr/X11R6/include
  58-X11LIB = /usr/X11R6/lib
  59-
  60-# Xinerama, comment if you don't want it
  61-XINERAMALIBS  = -lXinerama
  62-XINERAMAFLAGS = -DXINERAMA
  63-
  64-# freetype
  65-FREETYPELIBS = -lfontconfig -lXft
  66-FREETYPEINC = /usr/include/freetype2
  67-# OpenBSD (uncomment)
  68-#FREETYPEINC = $(X11INC)/freetype2
  69+PIXMANINC = /usr/include/pixman-1
  70+SWCPROTO = /usr/share/swc/swc.xml
  71 
  72 # includes and libs
  73-INCS = -I$(X11INC) -I$(FREETYPEINC)
  74-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
  75+INCS = -I$(PIXMANINC)
  76+LIBS = -lwayland-client -lxkbcommon -lwld
  77 
  78 # flags
  79-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
  80+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\"
  81 CFLAGS   = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
  82 LDFLAGS  = $(LIBS)
  83 
  84diff --git a/dmenu.c b/dmenu.c
  85index 6b8f51b..877c459 100644
  86--- a/dmenu.c
  87+++ b/dmenu.c
  88@@ -5,19 +5,18 @@
  89 #include <stdlib.h>
  90 #include <string.h>
  91 #include <strings.h>
  92+#include <sys/mman.h>
  93 #include <time.h>
  94 #include <unistd.h>
  95 
  96-#include <X11/Xlib.h>
  97-#include <X11/Xatom.h>
  98-#include <X11/Xutil.h>
  99-#ifdef XINERAMA
 100-#include <X11/extensions/Xinerama.h>
 101-#endif
 102-#include <X11/Xft/Xft.h>
 103+#include <wayland-client.h>
 104+#include <wld/wayland.h>
 105+#include <wld/wld.h>
 106+#include <xkbcommon/xkbcommon.h>
 107 
 108 #include "drw.h"
 109 #include "util.h"
 110+#include "swc-client-protocol.h"
 111 
 112 /* macros */
 113 #define INTERSECT(x,y,w,h,r)  (MAX(0, MIN((x)+(w),(r).x_org+(r).width)  - MAX((x),(r).x_org)) \
 114@@ -34,8 +33,16 @@ struct item {
 115 	int out;
 116 };
 117 
 118+struct xkb {
 119+	struct xkb_context *context;
 120+	struct xkb_state *state;
 121+	struct xkb_keymap *keymap;
 122+	xkb_mod_index_t ctrl, alt, shift;
 123+};
 124+
 125+static void paste(void);
 126+
 127 static char text[BUFSIZ] = "";
 128-static char *embed;
 129 static int bh, mw, mh;
 130 static int inputw = 0, promptw;
 131 static int lrpad; /* sum of left and right padding */
 132@@ -43,12 +50,21 @@ static size_t cursor;
 133 static struct item *items = NULL;
 134 static struct item *matches, *matchend;
 135 static struct item *prev, *curr, *next, *sel;
 136-static int mon = -1, screen;
 137-
 138-static Atom clip, utf8;
 139-static Display *dpy;
 140-static Window root, parentwin, win;
 141-static XIC xic;
 142+static int mon = -1;
 143+
 144+static struct wl_display *dpy;
 145+static struct wl_compositor *compositor;
 146+static struct wl_keyboard *kbd;
 147+static struct wl_seat *seat;
 148+static struct wl_shell *shell;
 149+static struct wl_surface *surface;
 150+static struct wl_data_device_manager *datadevman;
 151+static struct wl_data_device *datadev;
 152+static struct wl_data_offer *seloffer;
 153+static struct swc_screen *screen;
 154+static struct swc_panel_manager *panelman;
 155+static struct swc_panel *panel;
 156+static struct xkb xkb;
 157 
 158 static Drw *drw;
 159 static Clr *scheme[SchemeLast];
 160@@ -94,12 +110,10 @@ cleanup(void)
 161 {
 162 	size_t i;
 163 
 164-	XUngrabKey(dpy, AnyKey, AnyModifier, root);
 165 	for (i = 0; i < SchemeLast; i++)
 166 		free(scheme[i]);
 167 	drw_free(drw);
 168-	XSync(dpy, False);
 169-	XCloseDisplay(dpy);
 170+	wl_display_disconnect(dpy);
 171 }
 172 
 173 static char *
 174@@ -133,6 +147,7 @@ drawmenu(void)
 175 	struct item *item;
 176 	int x = 0, y = 0, w;
 177 
 178+	wld_set_target_surface(drw->renderer, drw->surface);
 179 	drw_setscheme(drw, scheme[SchemeNorm]);
 180 	drw_rect(drw, 0, 0, mw, mh, 1, 1);
 181 
 182@@ -172,42 +187,7 @@ drawmenu(void)
 183 			drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
 184 		}
 185 	}
 186-	drw_map(drw, win, 0, 0, mw, mh);
 187-}
 188-
 189-static void
 190-grabfocus(void)
 191-{
 192-	struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000  };
 193-	Window focuswin;
 194-	int i, revertwin;
 195-
 196-	for (i = 0; i < 100; ++i) {
 197-		XGetInputFocus(dpy, &focuswin, &revertwin);
 198-		if (focuswin == win)
 199-			return;
 200-		XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
 201-		nanosleep(&ts, NULL);
 202-	}
 203-	die("cannot grab focus");
 204-}
 205-
 206-static void
 207-grabkeyboard(void)
 208-{
 209-	struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000  };
 210-	int i;
 211-
 212-	if (embed)
 213-		return;
 214-	/* try to grab keyboard, we may have to wait for another process to ungrab */
 215-	for (i = 0; i < 1000; i++) {
 216-		if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
 217-		                  GrabModeAsync, CurrentTime) == GrabSuccess)
 218-			return;
 219-		nanosleep(&ts, NULL);
 220-	}
 221-	die("cannot grab keyboard");
 222+	drw_map(drw, surface, 0, 0, mw, mh);
 223 }
 224 
 225 static void
 226@@ -305,111 +285,105 @@ movewordedge(int dir)
 227 }
 228 
 229 static void
 230-keypress(XKeyEvent *ev)
 231+kbdkey(void *d, struct wl_keyboard *kbd, uint32_t serial, uint32_t time,
 232+       uint32_t key, uint32_t state)
 233 {
 234 	char buf[32];
 235 	int len;
 236-	KeySym ksym;
 237-	Status status;
 238+	xkb_keysym_t ksym = XKB_KEY_NoSymbol;
 239+	int ctrl = xkb_state_mod_index_is_active(xkb.state, xkb.ctrl, XKB_STATE_MODS_EFFECTIVE);
 240+	int shift = xkb_state_mod_index_is_active(xkb.state, xkb.shift, XKB_STATE_MODS_EFFECTIVE);
 241+	int alt = xkb_state_mod_index_is_active(xkb.state, xkb.alt, XKB_STATE_MODS_EFFECTIVE);
 242 
 243-	len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
 244-	switch (status) {
 245-	default: /* XLookupNone, XBufferOverflow */
 246-		return;
 247-	case XLookupChars:
 248-		goto insert;
 249-	case XLookupKeySym:
 250-	case XLookupBoth:
 251-		break;
 252-	}
 253+	if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
 254+		goto update_state;
 255 
 256-	if (ev->state & ControlMask) {
 257+	ksym = xkb_state_key_get_one_sym(xkb.state, key + 8);
 258+	if (ctrl) {
 259 		switch(ksym) {
 260-		case XK_a: ksym = XK_Home;      break;
 261-		case XK_b: ksym = XK_Left;      break;
 262-		case XK_c: ksym = XK_Escape;    break;
 263-		case XK_d: ksym = XK_Delete;    break;
 264-		case XK_e: ksym = XK_End;       break;
 265-		case XK_f: ksym = XK_Right;     break;
 266-		case XK_g: ksym = XK_Escape;    break;
 267-		case XK_h: ksym = XK_BackSpace; break;
 268-		case XK_i: ksym = XK_Tab;       break;
 269-		case XK_j: /* fallthrough */
 270-		case XK_J: /* fallthrough */
 271-		case XK_m: /* fallthrough */
 272-		case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break;
 273-		case XK_n: ksym = XK_Down;      break;
 274-		case XK_p: ksym = XK_Up;        break;
 275-
 276-		case XK_k: /* delete right */
 277+		case XKB_KEY_a: ksym = XKB_KEY_Home;      break;
 278+		case XKB_KEY_b: ksym = XKB_KEY_Left;      break;
 279+		case XKB_KEY_c: ksym = XKB_KEY_Escape;    break;
 280+		case XKB_KEY_d: ksym = XKB_KEY_Delete;    break;
 281+		case XKB_KEY_e: ksym = XKB_KEY_End;       break;
 282+		case XKB_KEY_f: ksym = XKB_KEY_Right;     break;
 283+		case XKB_KEY_g: ksym = XKB_KEY_Escape;    break;
 284+		case XKB_KEY_h: ksym = XKB_KEY_BackSpace; break;
 285+		case XKB_KEY_i: ksym = XKB_KEY_Tab;       break;
 286+		case XKB_KEY_j: /* fallthrough */
 287+		case XKB_KEY_J: /* fallthrough */
 288+		case XKB_KEY_m: /* fallthrough */
 289+		case XKB_KEY_M: ksym = XKB_KEY_Return; ctrl = 0; break;
 290+		case XKB_KEY_n: ksym = XKB_KEY_Down;      break;
 291+		case XKB_KEY_p: ksym = XKB_KEY_Up;        break;
 292+
 293+		case XKB_KEY_k: /* delete right */
 294 			text[cursor] = '\0';
 295 			match();
 296 			break;
 297-		case XK_u: /* delete left */
 298+		case XKB_KEY_u: /* delete left */
 299 			insert(NULL, 0 - cursor);
 300 			break;
 301-		case XK_w: /* delete word */
 302+		case XKB_KEY_w: /* delete word */
 303 			while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
 304 				insert(NULL, nextrune(-1) - cursor);
 305 			while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
 306 				insert(NULL, nextrune(-1) - cursor);
 307 			break;
 308-		case XK_y: /* paste selection */
 309-		case XK_Y:
 310-			XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
 311-			                  utf8, utf8, win, CurrentTime);
 312+		case XKB_KEY_y: /* paste selection */
 313+		case XKB_KEY_Y:
 314+			paste();
 315 			return;
 316-		case XK_Left:
 317+		case XKB_KEY_Left:
 318 			movewordedge(-1);
 319 			goto draw;
 320-		case XK_Right:
 321+		case XKB_KEY_Right:
 322 			movewordedge(+1);
 323 			goto draw;
 324-		case XK_Return:
 325-		case XK_KP_Enter:
 326+		case XKB_KEY_Return:
 327+		case XKB_KEY_KP_Enter:
 328 			break;
 329-		case XK_bracketleft:
 330+		case XKB_KEY_bracketleft:
 331 			cleanup();
 332 			exit(1);
 333 		default:
 334 			return;
 335 		}
 336-	} else if (ev->state & Mod1Mask) {
 337+	} else if (alt) {
 338 		switch(ksym) {
 339-		case XK_b:
 340+		case XKB_KEY_b:
 341 			movewordedge(-1);
 342 			goto draw;
 343-		case XK_f:
 344+		case XKB_KEY_f:
 345 			movewordedge(+1);
 346 			goto draw;
 347-		case XK_g: ksym = XK_Home;  break;
 348-		case XK_G: ksym = XK_End;   break;
 349-		case XK_h: ksym = XK_Up;    break;
 350-		case XK_j: ksym = XK_Next;  break;
 351-		case XK_k: ksym = XK_Prior; break;
 352-		case XK_l: ksym = XK_Down;  break;
 353+		case XKB_KEY_g: ksym = XKB_KEY_Home;  break;
 354+		case XKB_KEY_G: ksym = XKB_KEY_End;   break;
 355+		case XKB_KEY_h: ksym = XKB_KEY_Up;    break;
 356+		case XKB_KEY_j: ksym = XKB_KEY_Next;  break;
 357+		case XKB_KEY_k: ksym = XKB_KEY_Prior; break;
 358+		case XKB_KEY_l: ksym = XKB_KEY_Down;  break;
 359 		default:
 360 			return;
 361 		}
 362 	}
 363-
 364-	switch(ksym) {
 365+	switch (ksym) {
 366 	default:
 367-insert:
 368+		len = xkb_state_key_get_utf8(xkb.state, key + 8, buf, sizeof(buf));
 369 		if (!iscntrl(*buf))
 370 			insert(buf, len);
 371 		break;
 372-	case XK_Delete:
 373+	case XKB_KEY_Delete:
 374 		if (text[cursor] == '\0')
 375 			return;
 376 		cursor = nextrune(+1);
 377 		/* fallthrough */
 378-	case XK_BackSpace:
 379+	case XKB_KEY_BackSpace:
 380 		if (cursor == 0)
 381 			return;
 382 		insert(NULL, nextrune(-1) - cursor);
 383 		break;
 384-	case XK_End:
 385+	case XKB_KEY_End:
 386 		if (text[cursor] != '\0') {
 387 			cursor = strlen(text);
 388 			break;
 389@@ -425,10 +399,10 @@ insert:
 390 		}
 391 		sel = matchend;
 392 		break;
 393-	case XK_Escape:
 394+	case XKB_KEY_Escape:
 395 		cleanup();
 396 		exit(1);
 397-	case XK_Home:
 398+	case XKB_KEY_Home:
 399 		if (sel == matches) {
 400 			cursor = 0;
 401 			break;
 402@@ -436,7 +410,7 @@ insert:
 403 		sel = curr = matches;
 404 		calcoffsets();
 405 		break;
 406-	case XK_Left:
 407+	case XKB_KEY_Left:
 408 		if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
 409 			cursor = nextrune(-1);
 410 			break;
 411@@ -444,35 +418,35 @@ insert:
 412 		if (lines > 0)
 413 			return;
 414 		/* fallthrough */
 415-	case XK_Up:
 416+	case XKB_KEY_Up:
 417 		if (sel && sel->left && (sel = sel->left)->right == curr) {
 418 			curr = prev;
 419 			calcoffsets();
 420 		}
 421 		break;
 422-	case XK_Next:
 423+	case XKB_KEY_Next:
 424 		if (!next)
 425 			return;
 426 		sel = curr = next;
 427 		calcoffsets();
 428 		break;
 429-	case XK_Prior:
 430+	case XKB_KEY_Prior:
 431 		if (!prev)
 432 			return;
 433 		sel = curr = prev;
 434 		calcoffsets();
 435 		break;
 436-	case XK_Return:
 437-	case XK_KP_Enter:
 438-		puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
 439-		if (!(ev->state & ControlMask)) {
 440+	case XKB_KEY_Return:
 441+	case XKB_KEY_KP_Enter:
 442+		puts((sel && !shift) ? sel->text : text);
 443+		if (!ctrl) {
 444 			cleanup();
 445 			exit(0);
 446 		}
 447-		if (sel)
 448+		if(sel)
 449 			sel->out = 1;
 450 		break;
 451-	case XK_Right:
 452+	case XKB_KEY_Right:
 453 		if (text[cursor] != '\0') {
 454 			cursor = nextrune(+1);
 455 			break;
 456@@ -480,13 +454,13 @@ insert:
 457 		if (lines > 0)
 458 			return;
 459 		/* fallthrough */
 460-	case XK_Down:
 461+	case XKB_KEY_Down:
 462 		if (sel && sel->right && (sel = sel->right) == next) {
 463 			curr = next;
 464 			calcoffsets();
 465 		}
 466 		break;
 467-	case XK_Tab:
 468+	case XKB_KEY_Tab:
 469 		if (!sel)
 470 			return;
 471 		strncpy(text, sel->text, sizeof text - 1);
 472@@ -498,24 +472,28 @@ insert:
 473 
 474 draw:
 475 	drawmenu();
 476+
 477+update_state:
 478+	xkb_state_update_key(xkb.state, key + 8,
 479+			     state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
 480 }
 481 
 482 static void
 483 paste(void)
 484 {
 485-	char *p, *q;
 486-	int di;
 487-	unsigned long dl;
 488-	Atom da;
 489-
 490-	/* we have been given the current selection, now insert it into input */
 491-	if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
 492-	                   utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
 493-	    == Success && p) {
 494-		insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
 495-		XFree(p);
 496+	int fds[2], len;
 497+	char buf[BUFSIZ], *nl;
 498+
 499+	if (seloffer) {
 500+		pipe(fds);
 501+		wl_data_offer_receive(seloffer, "text/plain", fds[1]);
 502+		wl_display_flush(dpy);
 503+		close(fds[1]);
 504+		while((len = read(fds[0], buf, sizeof buf)) > 0)
 505+			insert(buf, (nl = strchr(buf, '\n')) ? nl - buf : len);
 506+		close(fds[0]);
 507+		drawmenu();
 508 	}
 509-	drawmenu();
 510 }
 511 
 512 static void
 513@@ -550,148 +528,207 @@ readstdin(void)
 514 static void
 515 run(void)
 516 {
 517-	XEvent ev;
 518+	while (wl_display_dispatch(dpy) != -1)
 519+		;
 520+}
 521 
 522-	while (!XNextEvent(dpy, &ev)) {
 523-		if (XFilterEvent(&ev, None))
 524-			continue;
 525-		switch(ev.type) {
 526-		case Expose:
 527-			if (ev.xexpose.count == 0)
 528-				drw_map(drw, win, 0, 0, mw, mh);
 529-			break;
 530-		case FocusIn:
 531-			/* regrab focus from parent window */
 532-			if (ev.xfocus.window != win)
 533-				grabfocus();
 534-			break;
 535-		case KeyPress:
 536-			keypress(&ev.xkey);
 537-			break;
 538-		case SelectionNotify:
 539-			if (ev.xselection.property == utf8)
 540-				paste();
 541-			break;
 542-		case VisibilityNotify:
 543-			if (ev.xvisibility.state != VisibilityUnobscured)
 544-				XRaiseWindow(dpy, win);
 545-			break;
 546-		}
 547+/* wayland event handlers */
 548+static void
 549+regglobal(void *d, struct wl_registry *r, uint32_t name, const char *interface, uint32_t version)
 550+{
 551+	if(strcmp(interface, "wl_compositor") == 0)
 552+		compositor = wl_registry_bind(r, name, &wl_compositor_interface, 1);
 553+	else if(strcmp(interface, "wl_shell") == 0)
 554+		shell = wl_registry_bind(r, name, &wl_shell_interface, 1);
 555+	else if(strcmp(interface, "wl_seat") == 0)
 556+		seat = wl_registry_bind(r, name, &wl_seat_interface, 1);
 557+	else if(strcmp(interface, "wl_data_device_manager") == 0)
 558+		datadevman = wl_registry_bind(r, name, &wl_data_device_manager_interface, 1);
 559+	else if(strcmp(interface, "swc_panel_manager") == 0)
 560+		panelman = wl_registry_bind(r, name, &swc_panel_manager_interface, 1);
 561+	else if (strcmp(interface, "swc_screen") == 0) {
 562+		if (mon != -1 && mon-- == 0)
 563+			screen = wl_registry_bind(r, name, &swc_screen_interface, 1);
 564 	}
 565 }
 566 
 567+static void
 568+regglobalremove(void *d, struct wl_registry *reg, uint32_t name)
 569+{
 570+}
 571+
 572+static const struct wl_registry_listener reglistener = { regglobal, regglobalremove };
 573+
 574+static void
 575+kbdenter(void *data, struct wl_keyboard *kbd, uint32_t serial,
 576+         struct wl_surface *surface, struct wl_array *keys)
 577+{
 578+}
 579+
 580+static void
 581+kbdleave(void *d, struct wl_keyboard *kbd, uint32_t serial,
 582+         struct wl_surface *surface)
 583+{
 584+	/* XXX: swc doesn't handle refocusing panels, so just exit for now */
 585+	cleanup();
 586+	exit(1);
 587+}
 588+
 589+/* kbdkey is defined above to reduce merge conflicts */
 590+
 591+static void
 592+kbdkeymap(void *d, struct wl_keyboard *kbd, uint32_t format, int32_t fd, uint32_t size)
 593+{
 594+	char *string;
 595+
 596+	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
 597+		close(fd);
 598+		return;
 599+	}
 600+
 601+	string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
 602+
 603+	if (string == MAP_FAILED) {
 604+		close(fd);
 605+		return;
 606+	}
 607+
 608+	xkb.keymap = xkb_keymap_new_from_string(xkb.context, string,
 609+						XKB_KEYMAP_FORMAT_TEXT_V1, 0);
 610+	munmap(string, size);
 611+	close(fd);
 612+	xkb.state = xkb_state_new(xkb.keymap);
 613+
 614+	xkb.ctrl = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_CTRL);
 615+	xkb.alt = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_ALT);
 616+	xkb.shift = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_SHIFT);
 617+}
 618+
 619+static void
 620+kbdmodifiers(void *d, struct wl_keyboard *kbd, uint32_t serial, uint32_t dep,
 621+             uint32_t lat, uint32_t lck, uint32_t grp)
 622+{
 623+	xkb_state_update_mask(xkb.state, dep, lat, lck, grp, 0, 0);
 624+}
 625+
 626+static const struct wl_keyboard_listener kbdlistener = {
 627+	kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers,
 628+};
 629+
 630+static void
 631+dataofferoffer(void *d, struct wl_data_offer *offer, const char *mimetype)
 632+{
 633+	if (strncmp(mimetype, "text/plain", 10) == 0)
 634+		wl_data_offer_set_user_data(offer, (void *)(uintptr_t) 1);
 635+}
 636+
 637+static const struct wl_data_offer_listener dataofferlistener = { dataofferoffer };
 638+
 639+static void
 640+datadevoffer(void *d, struct wl_data_device *datadev, struct wl_data_offer *offer)
 641+{
 642+	wl_data_offer_add_listener(offer, &dataofferlistener, NULL);
 643+}
 644+
 645+static void
 646+datadeventer(void *d, struct wl_data_device *datadev, uint32_t serial,
 647+             struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y,
 648+             struct wl_data_offer *offer)
 649+{
 650+}
 651+
 652+static void
 653+datadevleave(void *d, struct wl_data_device *datadev)
 654+{
 655+}
 656+
 657+static void
 658+datadevmotion(void *d, struct wl_data_device *datadev, uint32_t time,
 659+              wl_fixed_t x, wl_fixed_t y)
 660+{
 661+}
 662+
 663+static void
 664+datadevdrop(void *d, struct wl_data_device *datadev)
 665+{
 666+}
 667+
 668+static void
 669+datadevselection(void *d, struct wl_data_device *datadev, struct wl_data_offer *offer)
 670+{
 671+	if (offer && (uintptr_t) wl_data_offer_get_user_data(offer) == 1)
 672+		seloffer = offer;
 673+}
 674+
 675+static const struct wl_data_device_listener datadevlistener = {
 676+	datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop,
 677+	datadevselection,
 678+};
 679+
 680+static void
 681+paneldocked(void *d, struct swc_panel *panel, uint32_t length)
 682+{
 683+	mw = length;
 684+}
 685+
 686+static const struct swc_panel_listener panellistener = { paneldocked };
 687+
 688 static void
 689 setup(void)
 690 {
 691-	int x, y, i, j;
 692-	unsigned int du;
 693-	XSetWindowAttributes swa;
 694-	XIM xim;
 695-	Window w, dw, *dws;
 696-	XWindowAttributes wa;
 697-	XClassHint ch = {"dmenu", "dmenu"};
 698-#ifdef XINERAMA
 699-	XineramaScreenInfo *info;
 700-	Window pw;
 701-	int a, di, n, area = 0;
 702-#endif
 703+	int j;
 704+
 705+	if (!compositor || !seat || !panelman)
 706+		exit(1);
 707+
 708+	kbd = wl_seat_get_keyboard(seat);
 709+	wl_keyboard_add_listener(kbd, &kbdlistener, NULL);
 710+	datadev = wl_data_device_manager_get_data_device(datadevman, seat);
 711+	wl_data_device_add_listener(datadev, &datadevlistener, NULL);
 712+
 713+	xkb.context = xkb_context_new(0);
 714+
 715 	/* init appearance */
 716 	for (j = 0; j < SchemeLast; j++)
 717 		scheme[j] = drw_scm_create(drw, colors[j], 2);
 718 
 719-	clip = XInternAtom(dpy, "CLIPBOARD",   False);
 720-	utf8 = XInternAtom(dpy, "UTF8_STRING", False);
 721-
 722 	/* calculate menu geometry */
 723-	bh = drw->fonts->h + 2;
 724+	bh = drw->fonts->wld->height + 2;
 725 	lines = MAX(lines, 0);
 726 	mh = (lines + 1) * bh;
 727-#ifdef XINERAMA
 728-	i = 0;
 729-	if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
 730-		XGetInputFocus(dpy, &w, &di);
 731-		if (mon >= 0 && mon < n)
 732-			i = mon;
 733-		else if (w != root && w != PointerRoot && w != None) {
 734-			/* find top-level window containing current input focus */
 735-			do {
 736-				if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
 737-					XFree(dws);
 738-			} while (w != root && w != pw);
 739-			/* find xinerama screen with which the window intersects most */
 740-			if (XGetWindowAttributes(dpy, pw, &wa))
 741-				for (j = 0; j < n; j++)
 742-					if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
 743-						area = a;
 744-						i = j;
 745-					}
 746-		}
 747-		/* no focused window is on screen, so use pointer location instead */
 748-		if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
 749-			for (i = 0; i < n; i++)
 750-				if (INTERSECT(x, y, 1, 1, info[i]))
 751-					break;
 752-
 753-		x = info[i].x_org;
 754-		y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
 755-		mw = info[i].width;
 756-		XFree(info);
 757-	} else
 758-#endif
 759-	{
 760-		if (!XGetWindowAttributes(dpy, parentwin, &wa))
 761-			die("could not get embedding window attributes: 0x%lx",
 762-			    parentwin);
 763-		x = 0;
 764-		y = topbar ? 0 : wa.height - mh;
 765-		mw = wa.width;
 766-	}
 767+
 768+	/* create menu surface */
 769+	surface = wl_compositor_create_surface(compositor);
 770+
 771+	panel = swc_panel_manager_create_panel(panelman, surface);
 772+	swc_panel_add_listener(panel, &panellistener, NULL);
 773+	swc_panel_dock(panel, topbar ? SWC_PANEL_EDGE_TOP : SWC_PANEL_EDGE_BOTTOM, screen, 1);
 774+
 775+	wl_display_roundtrip(dpy);
 776+	if (!mw)
 777+		exit(1);
 778+
 779 	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
 780 	inputw = MIN(inputw, mw/3);
 781 	match();
 782 
 783-	/* create menu window */
 784-	swa.override_redirect = True;
 785-	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
 786-	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
 787-	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
 788-	                    CopyFromParent, CopyFromParent, CopyFromParent,
 789-	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
 790-	XSetClassHint(dpy, win, &ch);
 791-
 792-	/* open input methods */
 793-	xim = XOpenIM(dpy, NULL, NULL, NULL);
 794-	xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
 795-	                XNClientWindow, win, XNFocusWindow, win, NULL);
 796-
 797-	XMapRaised(dpy, win);
 798-	XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
 799-	if (embed) {
 800-		XSelectInput(dpy, parentwin, FocusChangeMask);
 801-		if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
 802-			for (i = 0; i < du && dws[i] != win; ++i)
 803-				XSelectInput(dpy, dws[i], FocusChangeMask);
 804-			XFree(dws);
 805-		}
 806-		grabfocus();
 807-	}
 808-	drw_resize(drw, mw, mh);
 809+	drw_resize(drw, surface, mw, mh);
 810 	drawmenu();
 811 }
 812 
 813 static void
 814 usage(void)
 815 {
 816-	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
 817-	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
 818+	fputs("usage: dmenu [-biv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
 819+	      "             [-nb color] [-nf color] [-sb color] [-sf color]\n", stderr);
 820 	exit(1);
 821 }
 822 
 823 int
 824 main(int argc, char *argv[])
 825 {
 826-	XWindowAttributes wa;
 827-	int i, fast = 0;
 828+	struct wl_registry *reg;
 829+	int i;
 830 
 831 	for (i = 1; i < argc; i++)
 832 		/* these options take no arguments */
 833@@ -700,8 +737,6 @@ main(int argc, char *argv[])
 834 			exit(0);
 835 		} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
 836 			topbar = 0;
 837-		else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
 838-			fast = 1;
 839 		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
 840 			fstrncmp = strncasecmp;
 841 			fstrstr = cistrstr;
 842@@ -724,41 +759,28 @@ main(int argc, char *argv[])
 843 			colors[SchemeSel][ColBg] = argv[++i];
 844 		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */
 845 			colors[SchemeSel][ColFg] = argv[++i];
 846-		else if (!strcmp(argv[i], "-w"))   /* embedding window id */
 847-			embed = argv[++i];
 848 		else
 849 			usage();
 850 
 851-	if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 852+	if (!setlocale(LC_CTYPE, ""))
 853 		fputs("warning: no locale support\n", stderr);
 854-	if (!XSetLocaleModifiers(""))
 855-		fputs("warning: no locale modifiers support\n", stderr);
 856-	if (!(dpy = XOpenDisplay(NULL)))
 857+	if (!(dpy = wl_display_connect(NULL)))
 858 		die("cannot open display");
 859-	screen = DefaultScreen(dpy);
 860-	root = RootWindow(dpy, screen);
 861-	if (!embed || !(parentwin = strtol(embed, NULL, 0)))
 862-		parentwin = root;
 863-	if (!XGetWindowAttributes(dpy, parentwin, &wa))
 864-		die("could not get embedding window attributes: 0x%lx",
 865-		    parentwin);
 866-	drw = drw_create(dpy, screen, root, wa.width, wa.height);
 867+	if (!(reg = wl_display_get_registry(dpy)))
 868+		die("cannot get registry");
 869+	wl_registry_add_listener(reg, &reglistener, NULL);
 870+	wl_display_roundtrip(dpy);
 871+	drw = drw_create(dpy);
 872 	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
 873 		die("no fonts could be loaded.");
 874-	lrpad = drw->fonts->h;
 875+	lrpad = drw->fonts->wld->height;
 876 
 877 #ifdef __OpenBSD__
 878 	if (pledge("stdio rpath", NULL) == -1)
 879 		die("pledge");
 880 #endif
 881 
 882-	if (fast && !isatty(0)) {
 883-		grabkeyboard();
 884-		readstdin();
 885-	} else {
 886-		readstdin();
 887-		grabkeyboard();
 888-	}
 889+	readstdin();
 890 	setup();
 891 	run();
 892 
 893diff --git a/drw.c b/drw.c
 894index 8fd1ca4..e4995a6 100644
 895--- a/drw.c
 896+++ b/drw.c
 897@@ -2,8 +2,9 @@
 898 #include <stdio.h>
 899 #include <stdlib.h>
 900 #include <string.h>
 901-#include <X11/Xlib.h>
 902-#include <X11/Xft/Xft.h>
 903+#include <wayland-client.h>
 904+#include <wld/wld.h>
 905+#include <wld/wayland.h>
 906 
 907 #include "drw.h"
 908 #include "util.h"
 909@@ -61,40 +62,33 @@ utf8decode(const char *c, long *u, size_t clen)
 910 }
 911 
 912 Drw *
 913-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
 914+drw_create(struct wl_display *dpy)
 915 {
 916 	Drw *drw = ecalloc(1, sizeof(Drw));
 917 
 918 	drw->dpy = dpy;
 919-	drw->screen = screen;
 920-	drw->root = root;
 921-	drw->w = w;
 922-	drw->h = h;
 923-	drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
 924-	drw->gc = XCreateGC(dpy, root, 0, NULL);
 925-	XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
 926+	drw->ctx = wld_wayland_create_context(dpy, WLD_ANY);
 927+	drw->renderer = wld_create_renderer(drw->ctx);
 928+	drw->fontctx = wld_font_create_context();
 929 
 930 	return drw;
 931 }
 932 
 933 void
 934-drw_resize(Drw *drw, unsigned int w, unsigned int h)
 935+drw_resize(Drw *drw, struct wl_surface *surface, unsigned int w, unsigned int h)
 936 {
 937-	if (!drw)
 938-		return;
 939-
 940-	drw->w = w;
 941-	drw->h = h;
 942-	if (drw->drawable)
 943-		XFreePixmap(drw->dpy, drw->drawable);
 944-	drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
 945+	if (drw->surface)
 946+		wld_destroy_surface(drw->surface);
 947+	drw->surface = wld_wayland_create_surface(drw->ctx, w, h, WLD_FORMAT_XRGB8888, 0, surface);
 948 }
 949 
 950 void
 951 drw_free(Drw *drw)
 952 {
 953-	XFreePixmap(drw->dpy, drw->drawable);
 954-	XFreeGC(drw->dpy, drw->gc);
 955+	wld_destroy_surface(drw->surface);
 956+	wld_destroy_renderer(drw->renderer);
 957+	wld_destroy_context(drw->ctx);
 958+	wld_font_destroy_context(drw->fontctx);
 959 	free(drw);
 960 }
 961 
 962@@ -102,11 +96,10 @@ drw_free(Drw *drw)
 963  * drw_fontset_create instead.
 964  */
 965 static Fnt *
 966-xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
 967+wldfont_create(Drw *drw, const char *fontname, FcPattern *pattern)
 968 {
 969 	Fnt *font;
 970-	XftFont *xfont = NULL;
 971-	FcPattern *pattern = NULL;
 972+	struct wld_font *wld = NULL;
 973 
 974 	if (fontname) {
 975 		/* Using the pattern found at font->xfont->pattern does not yield the
 976@@ -114,17 +107,17 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
 977 		 * FcNameParse; using the latter results in the desired fallback
 978 		 * behaviour whereas the former just results in missing-character
 979 		 * rectangles being drawn, at least with some fonts. */
 980-		if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
 981+		if (!(wld = wld_font_open_name(drw->fontctx, fontname))) {
 982 			fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
 983 			return NULL;
 984 		}
 985 		if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
 986 			fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
 987-			XftFontClose(drw->dpy, xfont);
 988+			wld_font_close(wld);
 989 			return NULL;
 990 		}
 991-	} else if (fontpattern) {
 992-		if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
 993+	} else if (pattern) {
 994+		if (!(wld = wld_font_open_pattern(drw->fontctx, pattern))) {
 995 			fprintf(stderr, "error, cannot load font from pattern.\n");
 996 			return NULL;
 997 		}
 998@@ -140,28 +133,26 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
 999 	 * and lots more all over the internet.
1000 	 */
1001 	FcBool iscol;
1002-	if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
1003-		XftFontClose(drw->dpy, xfont);
1004+	if(FcPatternGetBool(pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
1005+		wld_font_close(wld);
1006 		return NULL;
1007 	}
1008 
1009 	font = ecalloc(1, sizeof(Fnt));
1010-	font->xfont = xfont;
1011+	font->wld = wld;
1012 	font->pattern = pattern;
1013-	font->h = xfont->ascent + xfont->descent;
1014-	font->dpy = drw->dpy;
1015 
1016 	return font;
1017 }
1018 
1019 static void
1020-xfont_free(Fnt *font)
1021+wldfont_free(Fnt *font)
1022 {
1023 	if (!font)
1024 		return;
1025 	if (font->pattern)
1026 		FcPatternDestroy(font->pattern);
1027-	XftFontClose(font->dpy, font->xfont);
1028+	wld_font_close(font->wld);
1029 	free(font);
1030 }
1031 
1032@@ -175,7 +166,7 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
1033 		return NULL;
1034 
1035 	for (i = 1; i <= fontcount; i++) {
1036-		if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
1037+		if ((cur = wldfont_create(drw, fonts[fontcount - i], NULL))) {
1038 			cur->next = ret;
1039 			ret = cur;
1040 		}
1041@@ -188,7 +179,7 @@ drw_fontset_free(Fnt *font)
1042 {
1043 	if (font) {
1044 		drw_fontset_free(font->next);
1045-		xfont_free(font);
1046+		wldfont_free(font);
1047 	}
1048 }
1049 
1050@@ -197,10 +188,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
1051 {
1052 	if (!drw || !dest || !clrname)
1053 		return;
1054-
1055-	if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
1056-	                       DefaultColormap(drw->dpy, drw->screen),
1057-	                       clrname, dest))
1058+	if (!(wld_lookup_named_color(clrname, dest)))
1059 		die("error, cannot allocate color '%s'", clrname);
1060 }
1061 
1062@@ -213,7 +201,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
1063 	Clr *ret;
1064 
1065 	/* need at least two colors for a scheme */
1066-	if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
1067+	if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(*ret))))
1068 		return NULL;
1069 
1070 	for (i = 0; i < clrcount; i++)
1071@@ -240,11 +228,15 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
1072 {
1073 	if (!drw || !drw->scheme)
1074 		return;
1075-	XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
1076+	Clr color = invert ? drw->scheme[ColBg] : drw->scheme[ColFg];
1077 	if (filled)
1078-		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
1079-	else
1080-		XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
1081+		wld_fill_rectangle(drw->renderer, color, x, y, w, h);
1082+	else {
1083+		wld_fill_rectangle(drw->renderer, color, x, y, w, 1);
1084+		wld_fill_rectangle(drw->renderer, color, x + w - 1, y + 1, 1, h - 2);
1085+		wld_fill_rectangle(drw->renderer, color, x, y + 1, 1, h - 2);
1086+		wld_fill_rectangle(drw->renderer, color, x, y + h - 1, w, 1);
1087+	}
1088 }
1089 
1090 int
1091@@ -253,7 +245,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1092 	char buf[1024];
1093 	int ty;
1094 	unsigned int ew;
1095-	XftDraw *d = NULL;
1096 	Fnt *usedfont, *curfont, *nextfont;
1097 	size_t i, len;
1098 	int utf8strlen, utf8charlen, render = x || y || w || h;
1099@@ -262,7 +253,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1100 	FcCharSet *fccharset;
1101 	FcPattern *fcpattern;
1102 	FcPattern *match;
1103-	XftResult result;
1104+	FcResult result;
1105 	int charexists = 0;
1106 
1107 	if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
1108@@ -271,11 +262,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1109 	if (!render) {
1110 		w = ~w;
1111 	} else {
1112-		XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
1113-		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
1114-		d = XftDrawCreate(drw->dpy, drw->drawable,
1115-		                  DefaultVisual(drw->dpy, drw->screen),
1116-		                  DefaultColormap(drw->dpy, drw->screen));
1117+		wld_fill_rectangle(drw->renderer, drw->scheme[invert ? ColFg : ColBg], x, y, w, h);
1118 		x += lpad;
1119 		w -= lpad;
1120 	}
1121@@ -288,7 +275,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1122 		while (*text) {
1123 			utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
1124 			for (curfont = drw->fonts; curfont; curfont = curfont->next) {
1125-				charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
1126+				charexists = charexists || wld_font_ensure_char(curfont->wld,  utf8codepoint);
1127 				if (charexists) {
1128 					if (curfont == usedfont) {
1129 						utf8strlen += utf8charlen;
1130@@ -320,9 +307,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1131 						; /* NOP */
1132 
1133 				if (render) {
1134-					ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
1135-					XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
1136-					                  usedfont->xfont, x, ty, (XftChar8 *)buf, len);
1137+					ty = y + (h - usedfont->wld->height) / 2 + usedfont->wld->ascent;
1138+					wld_draw_text(drw->renderer, usedfont->wld, drw->scheme[invert ? ColBg : ColFg],
1139+					              x, ty, buf, len, NULL);
1140 				}
1141 				x += ew;
1142 				w -= ew;
1143@@ -343,7 +330,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1144 			FcCharSetAddChar(fccharset, utf8codepoint);
1145 
1146 			if (!drw->fonts->pattern) {
1147-				/* Refer to the comment in xfont_create for more information. */
1148+				/* Refer to the comment in wldfont_create for more information. */
1149 				die("the first font in the cache must be loaded from a font string.");
1150 			}
1151 
1152@@ -354,38 +341,37 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
1153 
1154 			FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
1155 			FcDefaultSubstitute(fcpattern);
1156-			match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
1157+			match = FcFontMatch(NULL, fcpattern, &result);
1158 
1159 			FcCharSetDestroy(fccharset);
1160 			FcPatternDestroy(fcpattern);
1161 
1162 			if (match) {
1163-				usedfont = xfont_create(drw, NULL, match);
1164-				if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
1165+				usedfont = wldfont_create(drw, NULL, match);
1166+				if (usedfont && wld_font_ensure_char(usedfont->wld, utf8codepoint)) {
1167 					for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
1168 						; /* NOP */
1169 					curfont->next = usedfont;
1170 				} else {
1171-					xfont_free(usedfont);
1172+					wldfont_free(usedfont);
1173 					usedfont = drw->fonts;
1174 				}
1175 			}
1176 		}
1177 	}
1178-	if (d)
1179-		XftDrawDestroy(d);
1180 
1181 	return x + (render ? w : 0);
1182 }
1183 
1184 void
1185-drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
1186+drw_map(Drw *drw, struct wl_surface *surface, int x, int y, unsigned int w, unsigned int h)
1187 {
1188 	if (!drw)
1189 		return;
1190 
1191-	XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
1192-	XSync(drw->dpy, False);
1193+	wl_surface_damage(surface, x, y, w, h);
1194+	wld_flush(drw->renderer);
1195+	wld_swap(drw->surface);
1196 }
1197 
1198 unsigned int
1199@@ -399,18 +385,19 @@ drw_fontset_getwidth(Drw *drw, const char *text)
1200 void
1201 drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
1202 {
1203-	XGlyphInfo ext;
1204+	struct wld_extents ext;
1205 
1206 	if (!font || !text)
1207 		return;
1208 
1209-	XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
1210+	wld_font_text_extents_n(font->wld, text, len, &ext);
1211 	if (w)
1212-		*w = ext.xOff;
1213+		*w = ext.advance;
1214 	if (h)
1215-		*h = font->h;
1216+		*h = font->wld->height;
1217 }
1218 
1219+#if 0
1220 Cur *
1221 drw_cur_create(Drw *drw, int shape)
1222 {
1223@@ -433,3 +420,4 @@ drw_cur_free(Drw *drw, Cur *cursor)
1224 	XFreeCursor(drw->dpy, cursor->cursor);
1225 	free(cursor);
1226 }
1227+#endif
1228diff --git a/drw.h b/drw.h
1229index 4c67419..1f1967e 100644
1230--- a/drw.h
1231+++ b/drw.h
1232@@ -1,34 +1,30 @@
1233 /* See LICENSE file for copyright and license details. */
1234 
1235-typedef struct {
1236-	Cursor cursor;
1237-} Cur;
1238+typedef void Cur;
1239 
1240 typedef struct Fnt {
1241-	Display *dpy;
1242-	unsigned int h;
1243-	XftFont *xfont;
1244+	struct wld_font *wld;
1245 	FcPattern *pattern;
1246 	struct Fnt *next;
1247 } Fnt;
1248 
1249 enum { ColFg, ColBg }; /* Clr scheme index */
1250-typedef XftColor Clr;
1251+typedef uint32_t Clr;
1252 
1253 typedef struct {
1254 	unsigned int w, h;
1255-	Display *dpy;
1256-	int screen;
1257-	Window root;
1258-	Drawable drawable;
1259-	GC gc;
1260+	struct wl_display *dpy;
1261+	struct wld_context *ctx;
1262+	struct wld_renderer *renderer;
1263+	struct wld_surface *surface;
1264+	struct wld_font_context *fontctx;
1265 	Clr *scheme;
1266 	Fnt *fonts;
1267 } Drw;
1268 
1269 /* Drawable abstraction */
1270-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
1271-void drw_resize(Drw *drw, unsigned int w, unsigned int h);
1272+Drw *drw_create(struct wl_display *dpy);
1273+void drw_resize(Drw *drw, struct wl_surface *surface, unsigned int w, unsigned int h);
1274 void drw_free(Drw *drw);
1275 
1276 /* Fnt abstraction */
1277@@ -54,4 +50,4 @@ void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled
1278 int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
1279 
1280 /* Map functions */
1281-void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
1282+void drw_map(Drw *drw, struct wl_surface *surface, int x, int y, unsigned int w, unsigned int h);
1283-- 
12842.30.1
1285