From d186aa8891ca777615b8138416c95565c05e0a09 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Thu, 27 Oct 2016 21:04:23 -0700 Subject: [PATCH] Port to wayland using wld and swc panels --- Makefile | 16 +- config.mk | 20 +- dmenu.c | 566 ++++++++++++++++++++++++++++-------------------------- drw.c | 130 ++++++------- drw.h | 26 ++- 5 files changed, 381 insertions(+), 377 deletions(-) diff --git a/Makefile b/Makefile index a03a95c..4046899 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = drw.c dmenu.c stest.c util.c +SRC = drw.c dmenu.c stest.c panel-protocol.c util.c OBJ = $(SRC:.c=.o) all: options dmenu stest @@ -20,10 +20,18 @@ options: config.h: cp config.def.h $@ -$(OBJ): arg.h config.h config.mk drw.h +swc-protocol.c: $(SWCPROTO) + @echo GEN $@ + @wayland-scanner code < $< > $@ -dmenu: dmenu.o drw.o util.o - $(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS) +swc-client-protocol.h: $(SWCPROTO) + @echo GEN $@ + @wayland-scanner client-header < $< > $@ + +$(OBJ): arg.h config.h config.mk drw.h swc-client-protocol.h + +dmenu: dmenu.o drw.o swc-protocol.o util.o + $(CC) -o $@ dmenu.o drw.o swc-protocol.o util.o $(LDFLAGS) stest: stest.o $(CC) -o $@ stest.o $(LDFLAGS) diff --git a/config.mk b/config.mk index 0929b4a..7e747ff 100644 --- a/config.mk +++ b/config.mk @@ -5,25 +5,15 @@ VERSION = 4.9 PREFIX = /usr/local MANPREFIX = $(PREFIX)/share/man -X11INC = /usr/X11R6/include -X11LIB = /usr/X11R6/lib - -# Xinerama, comment if you don't want it -XINERAMALIBS = -lXinerama -XINERAMAFLAGS = -DXINERAMA - -# freetype -FREETYPELIBS = -lfontconfig -lXft -FREETYPEINC = /usr/include/freetype2 -# OpenBSD (uncomment) -#FREETYPEINC = $(X11INC)/freetype2 +PIXMANINC = /usr/include/pixman-1 +SWCPROTO = /usr/share/swc/swc.xml # includes and libs -INCS = -I$(X11INC) -I$(FREETYPEINC) -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) +INCS = -I$(PIXMANINC) +LIBS = -lwayland-client -lxkbcommon -lwld # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) LDFLAGS = $(LIBS) diff --git a/dmenu.c b/dmenu.c index 6b8f51b..877c459 100644 --- a/dmenu.c +++ b/dmenu.c @@ -5,19 +5,18 @@ #include #include #include +#include #include #include -#include -#include -#include -#ifdef XINERAMA -#include -#endif -#include +#include +#include +#include +#include #include "drw.h" #include "util.h" +#include "swc-client-protocol.h" /* macros */ #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ @@ -34,8 +33,16 @@ struct item { int out; }; +struct xkb { + struct xkb_context *context; + struct xkb_state *state; + struct xkb_keymap *keymap; + xkb_mod_index_t ctrl, alt, shift; +}; + +static void paste(void); + static char text[BUFSIZ] = ""; -static char *embed; static int bh, mw, mh; static int inputw = 0, promptw; static int lrpad; /* sum of left and right padding */ @@ -43,12 +50,21 @@ static size_t cursor; static struct item *items = NULL; static struct item *matches, *matchend; static struct item *prev, *curr, *next, *sel; -static int mon = -1, screen; - -static Atom clip, utf8; -static Display *dpy; -static Window root, parentwin, win; -static XIC xic; +static int mon = -1; + +static struct wl_display *dpy; +static struct wl_compositor *compositor; +static struct wl_keyboard *kbd; +static struct wl_seat *seat; +static struct wl_shell *shell; +static struct wl_surface *surface; +static struct wl_data_device_manager *datadevman; +static struct wl_data_device *datadev; +static struct wl_data_offer *seloffer; +static struct swc_screen *screen; +static struct swc_panel_manager *panelman; +static struct swc_panel *panel; +static struct xkb xkb; static Drw *drw; static Clr *scheme[SchemeLast]; @@ -94,12 +110,10 @@ cleanup(void) { size_t i; - XUngrabKey(dpy, AnyKey, AnyModifier, root); for (i = 0; i < SchemeLast; i++) free(scheme[i]); drw_free(drw); - XSync(dpy, False); - XCloseDisplay(dpy); + wl_display_disconnect(dpy); } static char * @@ -133,6 +147,7 @@ drawmenu(void) struct item *item; int x = 0, y = 0, w; + wld_set_target_surface(drw->renderer, drw->surface); drw_setscheme(drw, scheme[SchemeNorm]); drw_rect(drw, 0, 0, mw, mh, 1, 1); @@ -172,42 +187,7 @@ drawmenu(void) drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); } } - drw_map(drw, win, 0, 0, mw, mh); -} - -static void -grabfocus(void) -{ - struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; - Window focuswin; - int i, revertwin; - - for (i = 0; i < 100; ++i) { - XGetInputFocus(dpy, &focuswin, &revertwin); - if (focuswin == win) - return; - XSetInputFocus(dpy, win, RevertToParent, CurrentTime); - nanosleep(&ts, NULL); - } - die("cannot grab focus"); -} - -static void -grabkeyboard(void) -{ - struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; - int i; - - if (embed) - return; - /* try to grab keyboard, we may have to wait for another process to ungrab */ - for (i = 0; i < 1000; i++) { - if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, - GrabModeAsync, CurrentTime) == GrabSuccess) - return; - nanosleep(&ts, NULL); - } - die("cannot grab keyboard"); + drw_map(drw, surface, 0, 0, mw, mh); } static void @@ -305,111 +285,105 @@ movewordedge(int dir) } static void -keypress(XKeyEvent *ev) +kbdkey(void *d, struct wl_keyboard *kbd, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) { char buf[32]; int len; - KeySym ksym; - Status status; + xkb_keysym_t ksym = XKB_KEY_NoSymbol; + int ctrl = xkb_state_mod_index_is_active(xkb.state, xkb.ctrl, XKB_STATE_MODS_EFFECTIVE); + int shift = xkb_state_mod_index_is_active(xkb.state, xkb.shift, XKB_STATE_MODS_EFFECTIVE); + int alt = xkb_state_mod_index_is_active(xkb.state, xkb.alt, XKB_STATE_MODS_EFFECTIVE); - len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status); - switch (status) { - default: /* XLookupNone, XBufferOverflow */ - return; - case XLookupChars: - goto insert; - case XLookupKeySym: - case XLookupBoth: - break; - } + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) + goto update_state; - if (ev->state & ControlMask) { + ksym = xkb_state_key_get_one_sym(xkb.state, key + 8); + if (ctrl) { switch(ksym) { - case XK_a: ksym = XK_Home; break; - case XK_b: ksym = XK_Left; break; - case XK_c: ksym = XK_Escape; break; - case XK_d: ksym = XK_Delete; break; - case XK_e: ksym = XK_End; break; - case XK_f: ksym = XK_Right; break; - case XK_g: ksym = XK_Escape; break; - case XK_h: ksym = XK_BackSpace; break; - case XK_i: ksym = XK_Tab; break; - case XK_j: /* fallthrough */ - case XK_J: /* fallthrough */ - case XK_m: /* fallthrough */ - case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break; - case XK_n: ksym = XK_Down; break; - case XK_p: ksym = XK_Up; break; - - case XK_k: /* delete right */ + case XKB_KEY_a: ksym = XKB_KEY_Home; break; + case XKB_KEY_b: ksym = XKB_KEY_Left; break; + case XKB_KEY_c: ksym = XKB_KEY_Escape; break; + case XKB_KEY_d: ksym = XKB_KEY_Delete; break; + case XKB_KEY_e: ksym = XKB_KEY_End; break; + case XKB_KEY_f: ksym = XKB_KEY_Right; break; + case XKB_KEY_g: ksym = XKB_KEY_Escape; break; + case XKB_KEY_h: ksym = XKB_KEY_BackSpace; break; + case XKB_KEY_i: ksym = XKB_KEY_Tab; break; + case XKB_KEY_j: /* fallthrough */ + case XKB_KEY_J: /* fallthrough */ + case XKB_KEY_m: /* fallthrough */ + case XKB_KEY_M: ksym = XKB_KEY_Return; ctrl = 0; break; + case XKB_KEY_n: ksym = XKB_KEY_Down; break; + case XKB_KEY_p: ksym = XKB_KEY_Up; break; + + case XKB_KEY_k: /* delete right */ text[cursor] = '\0'; match(); break; - case XK_u: /* delete left */ + case XKB_KEY_u: /* delete left */ insert(NULL, 0 - cursor); break; - case XK_w: /* delete word */ + case XKB_KEY_w: /* delete word */ while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) insert(NULL, nextrune(-1) - cursor); while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) insert(NULL, nextrune(-1) - cursor); break; - case XK_y: /* paste selection */ - case XK_Y: - XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, - utf8, utf8, win, CurrentTime); + case XKB_KEY_y: /* paste selection */ + case XKB_KEY_Y: + paste(); return; - case XK_Left: + case XKB_KEY_Left: movewordedge(-1); goto draw; - case XK_Right: + case XKB_KEY_Right: movewordedge(+1); goto draw; - case XK_Return: - case XK_KP_Enter: + case XKB_KEY_Return: + case XKB_KEY_KP_Enter: break; - case XK_bracketleft: + case XKB_KEY_bracketleft: cleanup(); exit(1); default: return; } - } else if (ev->state & Mod1Mask) { + } else if (alt) { switch(ksym) { - case XK_b: + case XKB_KEY_b: movewordedge(-1); goto draw; - case XK_f: + case XKB_KEY_f: movewordedge(+1); goto draw; - case XK_g: ksym = XK_Home; break; - case XK_G: ksym = XK_End; break; - case XK_h: ksym = XK_Up; break; - case XK_j: ksym = XK_Next; break; - case XK_k: ksym = XK_Prior; break; - case XK_l: ksym = XK_Down; break; + case XKB_KEY_g: ksym = XKB_KEY_Home; break; + case XKB_KEY_G: ksym = XKB_KEY_End; break; + case XKB_KEY_h: ksym = XKB_KEY_Up; break; + case XKB_KEY_j: ksym = XKB_KEY_Next; break; + case XKB_KEY_k: ksym = XKB_KEY_Prior; break; + case XKB_KEY_l: ksym = XKB_KEY_Down; break; default: return; } } - - switch(ksym) { + switch (ksym) { default: -insert: + len = xkb_state_key_get_utf8(xkb.state, key + 8, buf, sizeof(buf)); if (!iscntrl(*buf)) insert(buf, len); break; - case XK_Delete: + case XKB_KEY_Delete: if (text[cursor] == '\0') return; cursor = nextrune(+1); /* fallthrough */ - case XK_BackSpace: + case XKB_KEY_BackSpace: if (cursor == 0) return; insert(NULL, nextrune(-1) - cursor); break; - case XK_End: + case XKB_KEY_End: if (text[cursor] != '\0') { cursor = strlen(text); break; @@ -425,10 +399,10 @@ insert: } sel = matchend; break; - case XK_Escape: + case XKB_KEY_Escape: cleanup(); exit(1); - case XK_Home: + case XKB_KEY_Home: if (sel == matches) { cursor = 0; break; @@ -436,7 +410,7 @@ insert: sel = curr = matches; calcoffsets(); break; - case XK_Left: + case XKB_KEY_Left: if (cursor > 0 && (!sel || !sel->left || lines > 0)) { cursor = nextrune(-1); break; @@ -444,35 +418,35 @@ insert: if (lines > 0) return; /* fallthrough */ - case XK_Up: + case XKB_KEY_Up: if (sel && sel->left && (sel = sel->left)->right == curr) { curr = prev; calcoffsets(); } break; - case XK_Next: + case XKB_KEY_Next: if (!next) return; sel = curr = next; calcoffsets(); break; - case XK_Prior: + case XKB_KEY_Prior: if (!prev) return; sel = curr = prev; calcoffsets(); break; - case XK_Return: - case XK_KP_Enter: - puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); - if (!(ev->state & ControlMask)) { + case XKB_KEY_Return: + case XKB_KEY_KP_Enter: + puts((sel && !shift) ? sel->text : text); + if (!ctrl) { cleanup(); exit(0); } - if (sel) + if(sel) sel->out = 1; break; - case XK_Right: + case XKB_KEY_Right: if (text[cursor] != '\0') { cursor = nextrune(+1); break; @@ -480,13 +454,13 @@ insert: if (lines > 0) return; /* fallthrough */ - case XK_Down: + case XKB_KEY_Down: if (sel && sel->right && (sel = sel->right) == next) { curr = next; calcoffsets(); } break; - case XK_Tab: + case XKB_KEY_Tab: if (!sel) return; strncpy(text, sel->text, sizeof text - 1); @@ -498,24 +472,28 @@ insert: draw: drawmenu(); + +update_state: + xkb_state_update_key(xkb.state, key + 8, + state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); } static void paste(void) { - char *p, *q; - int di; - unsigned long dl; - Atom da; - - /* we have been given the current selection, now insert it into input */ - if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False, - utf8, &da, &di, &dl, &dl, (unsigned char **)&p) - == Success && p) { - insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); - XFree(p); + int fds[2], len; + char buf[BUFSIZ], *nl; + + if (seloffer) { + pipe(fds); + wl_data_offer_receive(seloffer, "text/plain", fds[1]); + wl_display_flush(dpy); + close(fds[1]); + while((len = read(fds[0], buf, sizeof buf)) > 0) + insert(buf, (nl = strchr(buf, '\n')) ? nl - buf : len); + close(fds[0]); + drawmenu(); } - drawmenu(); } static void @@ -550,148 +528,207 @@ readstdin(void) static void run(void) { - XEvent ev; + while (wl_display_dispatch(dpy) != -1) + ; +} - while (!XNextEvent(dpy, &ev)) { - if (XFilterEvent(&ev, None)) - continue; - switch(ev.type) { - case Expose: - if (ev.xexpose.count == 0) - drw_map(drw, win, 0, 0, mw, mh); - break; - case FocusIn: - /* regrab focus from parent window */ - if (ev.xfocus.window != win) - grabfocus(); - break; - case KeyPress: - keypress(&ev.xkey); - break; - case SelectionNotify: - if (ev.xselection.property == utf8) - paste(); - break; - case VisibilityNotify: - if (ev.xvisibility.state != VisibilityUnobscured) - XRaiseWindow(dpy, win); - break; - } +/* wayland event handlers */ +static void +regglobal(void *d, struct wl_registry *r, uint32_t name, const char *interface, uint32_t version) +{ + if(strcmp(interface, "wl_compositor") == 0) + compositor = wl_registry_bind(r, name, &wl_compositor_interface, 1); + else if(strcmp(interface, "wl_shell") == 0) + shell = wl_registry_bind(r, name, &wl_shell_interface, 1); + else if(strcmp(interface, "wl_seat") == 0) + seat = wl_registry_bind(r, name, &wl_seat_interface, 1); + else if(strcmp(interface, "wl_data_device_manager") == 0) + datadevman = wl_registry_bind(r, name, &wl_data_device_manager_interface, 1); + else if(strcmp(interface, "swc_panel_manager") == 0) + panelman = wl_registry_bind(r, name, &swc_panel_manager_interface, 1); + else if (strcmp(interface, "swc_screen") == 0) { + if (mon != -1 && mon-- == 0) + screen = wl_registry_bind(r, name, &swc_screen_interface, 1); } } +static void +regglobalremove(void *d, struct wl_registry *reg, uint32_t name) +{ +} + +static const struct wl_registry_listener reglistener = { regglobal, regglobalremove }; + +static void +kbdenter(void *data, struct wl_keyboard *kbd, uint32_t serial, + struct wl_surface *surface, struct wl_array *keys) +{ +} + +static void +kbdleave(void *d, struct wl_keyboard *kbd, uint32_t serial, + struct wl_surface *surface) +{ + /* XXX: swc doesn't handle refocusing panels, so just exit for now */ + cleanup(); + exit(1); +} + +/* kbdkey is defined above to reduce merge conflicts */ + +static void +kbdkeymap(void *d, struct wl_keyboard *kbd, uint32_t format, int32_t fd, uint32_t size) +{ + char *string; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + + if (string == MAP_FAILED) { + close(fd); + return; + } + + xkb.keymap = xkb_keymap_new_from_string(xkb.context, string, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(string, size); + close(fd); + xkb.state = xkb_state_new(xkb.keymap); + + xkb.ctrl = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_CTRL); + xkb.alt = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_ALT); + xkb.shift = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_SHIFT); +} + +static void +kbdmodifiers(void *d, struct wl_keyboard *kbd, uint32_t serial, uint32_t dep, + uint32_t lat, uint32_t lck, uint32_t grp) +{ + xkb_state_update_mask(xkb.state, dep, lat, lck, grp, 0, 0); +} + +static const struct wl_keyboard_listener kbdlistener = { + kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, +}; + +static void +dataofferoffer(void *d, struct wl_data_offer *offer, const char *mimetype) +{ + if (strncmp(mimetype, "text/plain", 10) == 0) + wl_data_offer_set_user_data(offer, (void *)(uintptr_t) 1); +} + +static const struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; + +static void +datadevoffer(void *d, struct wl_data_device *datadev, struct wl_data_offer *offer) +{ + wl_data_offer_add_listener(offer, &dataofferlistener, NULL); +} + +static void +datadeventer(void *d, struct wl_data_device *datadev, uint32_t serial, + struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, + struct wl_data_offer *offer) +{ +} + +static void +datadevleave(void *d, struct wl_data_device *datadev) +{ +} + +static void +datadevmotion(void *d, struct wl_data_device *datadev, uint32_t time, + wl_fixed_t x, wl_fixed_t y) +{ +} + +static void +datadevdrop(void *d, struct wl_data_device *datadev) +{ +} + +static void +datadevselection(void *d, struct wl_data_device *datadev, struct wl_data_offer *offer) +{ + if (offer && (uintptr_t) wl_data_offer_get_user_data(offer) == 1) + seloffer = offer; +} + +static const struct wl_data_device_listener datadevlistener = { + datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, + datadevselection, +}; + +static void +paneldocked(void *d, struct swc_panel *panel, uint32_t length) +{ + mw = length; +} + +static const struct swc_panel_listener panellistener = { paneldocked }; + static void setup(void) { - int x, y, i, j; - unsigned int du; - XSetWindowAttributes swa; - XIM xim; - Window w, dw, *dws; - XWindowAttributes wa; - XClassHint ch = {"dmenu", "dmenu"}; -#ifdef XINERAMA - XineramaScreenInfo *info; - Window pw; - int a, di, n, area = 0; -#endif + int j; + + if (!compositor || !seat || !panelman) + exit(1); + + kbd = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(kbd, &kbdlistener, NULL); + datadev = wl_data_device_manager_get_data_device(datadevman, seat); + wl_data_device_add_listener(datadev, &datadevlistener, NULL); + + xkb.context = xkb_context_new(0); + /* init appearance */ for (j = 0; j < SchemeLast; j++) scheme[j] = drw_scm_create(drw, colors[j], 2); - clip = XInternAtom(dpy, "CLIPBOARD", False); - utf8 = XInternAtom(dpy, "UTF8_STRING", False); - /* calculate menu geometry */ - bh = drw->fonts->h + 2; + bh = drw->fonts->wld->height + 2; lines = MAX(lines, 0); mh = (lines + 1) * bh; -#ifdef XINERAMA - i = 0; - if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { - XGetInputFocus(dpy, &w, &di); - if (mon >= 0 && mon < n) - i = mon; - else if (w != root && w != PointerRoot && w != None) { - /* find top-level window containing current input focus */ - do { - if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) - XFree(dws); - } while (w != root && w != pw); - /* find xinerama screen with which the window intersects most */ - if (XGetWindowAttributes(dpy, pw, &wa)) - for (j = 0; j < n; j++) - if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { - area = a; - i = j; - } - } - /* no focused window is on screen, so use pointer location instead */ - if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) - for (i = 0; i < n; i++) - if (INTERSECT(x, y, 1, 1, info[i])) - break; - - x = info[i].x_org; - y = info[i].y_org + (topbar ? 0 : info[i].height - mh); - mw = info[i].width; - XFree(info); - } else -#endif - { - if (!XGetWindowAttributes(dpy, parentwin, &wa)) - die("could not get embedding window attributes: 0x%lx", - parentwin); - x = 0; - y = topbar ? 0 : wa.height - mh; - mw = wa.width; - } + + /* create menu surface */ + surface = wl_compositor_create_surface(compositor); + + panel = swc_panel_manager_create_panel(panelman, surface); + swc_panel_add_listener(panel, &panellistener, NULL); + swc_panel_dock(panel, topbar ? SWC_PANEL_EDGE_TOP : SWC_PANEL_EDGE_BOTTOM, screen, 1); + + wl_display_roundtrip(dpy); + if (!mw) + exit(1); + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; inputw = MIN(inputw, mw/3); match(); - /* create menu window */ - swa.override_redirect = True; - swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; - swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, - CopyFromParent, CopyFromParent, CopyFromParent, - CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); - XSetClassHint(dpy, win, &ch); - - /* open input methods */ - xim = XOpenIM(dpy, NULL, NULL, NULL); - xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, win, XNFocusWindow, win, NULL); - - XMapRaised(dpy, win); - XSetInputFocus(dpy, win, RevertToParent, CurrentTime); - if (embed) { - XSelectInput(dpy, parentwin, FocusChangeMask); - if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { - for (i = 0; i < du && dws[i] != win; ++i) - XSelectInput(dpy, dws[i], FocusChangeMask); - XFree(dws); - } - grabfocus(); - } - drw_resize(drw, mw, mh); + drw_resize(drw, surface, mw, mh); drawmenu(); } static void usage(void) { - fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); + fputs("usage: dmenu [-biv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color]\n", stderr); exit(1); } int main(int argc, char *argv[]) { - XWindowAttributes wa; - int i, fast = 0; + struct wl_registry *reg; + int i; for (i = 1; i < argc; i++) /* these options take no arguments */ @@ -700,8 +737,6 @@ main(int argc, char *argv[]) exit(0); } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ topbar = 0; - else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ - fast = 1; else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ fstrncmp = strncasecmp; fstrstr = cistrstr; @@ -724,41 +759,28 @@ main(int argc, char *argv[]) colors[SchemeSel][ColBg] = argv[++i]; else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ colors[SchemeSel][ColFg] = argv[++i]; - else if (!strcmp(argv[i], "-w")) /* embedding window id */ - embed = argv[++i]; else usage(); - if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + if (!setlocale(LC_CTYPE, "")) fputs("warning: no locale support\n", stderr); - if (!XSetLocaleModifiers("")) - fputs("warning: no locale modifiers support\n", stderr); - if (!(dpy = XOpenDisplay(NULL))) + if (!(dpy = wl_display_connect(NULL))) die("cannot open display"); - screen = DefaultScreen(dpy); - root = RootWindow(dpy, screen); - if (!embed || !(parentwin = strtol(embed, NULL, 0))) - parentwin = root; - if (!XGetWindowAttributes(dpy, parentwin, &wa)) - die("could not get embedding window attributes: 0x%lx", - parentwin); - drw = drw_create(dpy, screen, root, wa.width, wa.height); + if (!(reg = wl_display_get_registry(dpy))) + die("cannot get registry"); + wl_registry_add_listener(reg, ®listener, NULL); + wl_display_roundtrip(dpy); + drw = drw_create(dpy); if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) die("no fonts could be loaded."); - lrpad = drw->fonts->h; + lrpad = drw->fonts->wld->height; #ifdef __OpenBSD__ if (pledge("stdio rpath", NULL) == -1) die("pledge"); #endif - if (fast && !isatty(0)) { - grabkeyboard(); - readstdin(); - } else { - readstdin(); - grabkeyboard(); - } + readstdin(); setup(); run(); diff --git a/drw.c b/drw.c index 8fd1ca4..e4995a6 100644 --- a/drw.c +++ b/drw.c @@ -2,8 +2,9 @@ #include #include #include -#include -#include +#include +#include +#include #include "drw.h" #include "util.h" @@ -61,40 +62,33 @@ utf8decode(const char *c, long *u, size_t clen) } Drw * -drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +drw_create(struct wl_display *dpy) { Drw *drw = ecalloc(1, sizeof(Drw)); drw->dpy = dpy; - drw->screen = screen; - drw->root = root; - drw->w = w; - drw->h = h; - drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); - drw->gc = XCreateGC(dpy, root, 0, NULL); - XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + drw->ctx = wld_wayland_create_context(dpy, WLD_ANY); + drw->renderer = wld_create_renderer(drw->ctx); + drw->fontctx = wld_font_create_context(); return drw; } void -drw_resize(Drw *drw, unsigned int w, unsigned int h) +drw_resize(Drw *drw, struct wl_surface *surface, unsigned int w, unsigned int h) { - if (!drw) - return; - - drw->w = w; - drw->h = h; - if (drw->drawable) - XFreePixmap(drw->dpy, drw->drawable); - drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); + if (drw->surface) + wld_destroy_surface(drw->surface); + drw->surface = wld_wayland_create_surface(drw->ctx, w, h, WLD_FORMAT_XRGB8888, 0, surface); } void drw_free(Drw *drw) { - XFreePixmap(drw->dpy, drw->drawable); - XFreeGC(drw->dpy, drw->gc); + wld_destroy_surface(drw->surface); + wld_destroy_renderer(drw->renderer); + wld_destroy_context(drw->ctx); + wld_font_destroy_context(drw->fontctx); free(drw); } @@ -102,11 +96,10 @@ drw_free(Drw *drw) * drw_fontset_create instead. */ static Fnt * -xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +wldfont_create(Drw *drw, const char *fontname, FcPattern *pattern) { Fnt *font; - XftFont *xfont = NULL; - FcPattern *pattern = NULL; + struct wld_font *wld = NULL; if (fontname) { /* Using the pattern found at font->xfont->pattern does not yield the @@ -114,17 +107,17 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) * FcNameParse; using the latter results in the desired fallback * behaviour whereas the former just results in missing-character * rectangles being drawn, at least with some fonts. */ - if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + if (!(wld = wld_font_open_name(drw->fontctx, fontname))) { fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); return NULL; } if (!(pattern = FcNameParse((FcChar8 *) fontname))) { fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); - XftFontClose(drw->dpy, xfont); + wld_font_close(wld); return NULL; } - } else if (fontpattern) { - if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + } else if (pattern) { + if (!(wld = wld_font_open_pattern(drw->fontctx, pattern))) { fprintf(stderr, "error, cannot load font from pattern.\n"); return NULL; } @@ -140,28 +133,26 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) * and lots more all over the internet. */ FcBool iscol; - if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { - XftFontClose(drw->dpy, xfont); + if(FcPatternGetBool(pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + wld_font_close(wld); return NULL; } font = ecalloc(1, sizeof(Fnt)); - font->xfont = xfont; + font->wld = wld; font->pattern = pattern; - font->h = xfont->ascent + xfont->descent; - font->dpy = drw->dpy; return font; } static void -xfont_free(Fnt *font) +wldfont_free(Fnt *font) { if (!font) return; if (font->pattern) FcPatternDestroy(font->pattern); - XftFontClose(font->dpy, font->xfont); + wld_font_close(font->wld); free(font); } @@ -175,7 +166,7 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) return NULL; for (i = 1; i <= fontcount; i++) { - if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + if ((cur = wldfont_create(drw, fonts[fontcount - i], NULL))) { cur->next = ret; ret = cur; } @@ -188,7 +179,7 @@ drw_fontset_free(Fnt *font) { if (font) { drw_fontset_free(font->next); - xfont_free(font); + wldfont_free(font); } } @@ -197,10 +188,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) { if (!drw || !dest || !clrname) return; - - if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), - DefaultColormap(drw->dpy, drw->screen), - clrname, dest)) + if (!(wld_lookup_named_color(clrname, dest))) die("error, cannot allocate color '%s'", clrname); } @@ -213,7 +201,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) Clr *ret; /* need at least two colors for a scheme */ - if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(*ret)))) return NULL; for (i = 0; i < clrcount; i++) @@ -240,11 +228,15 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int { if (!drw || !drw->scheme) return; - XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + Clr color = invert ? drw->scheme[ColBg] : drw->scheme[ColFg]; if (filled) - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); - else - XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); + wld_fill_rectangle(drw->renderer, color, x, y, w, h); + else { + wld_fill_rectangle(drw->renderer, color, x, y, w, 1); + wld_fill_rectangle(drw->renderer, color, x + w - 1, y + 1, 1, h - 2); + wld_fill_rectangle(drw->renderer, color, x, y + 1, 1, h - 2); + wld_fill_rectangle(drw->renderer, color, x, y + h - 1, w, 1); + } } int @@ -253,7 +245,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp char buf[1024]; int ty; unsigned int ew; - XftDraw *d = NULL; Fnt *usedfont, *curfont, *nextfont; size_t i, len; int utf8strlen, utf8charlen, render = x || y || w || h; @@ -262,7 +253,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp FcCharSet *fccharset; FcPattern *fcpattern; FcPattern *match; - XftResult result; + FcResult result; int charexists = 0; if (!drw || (render && !drw->scheme) || !text || !drw->fonts) @@ -271,11 +262,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp if (!render) { w = ~w; } else { - XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); - d = XftDrawCreate(drw->dpy, drw->drawable, - DefaultVisual(drw->dpy, drw->screen), - DefaultColormap(drw->dpy, drw->screen)); + wld_fill_rectangle(drw->renderer, drw->scheme[invert ? ColFg : ColBg], x, y, w, h); x += lpad; w -= lpad; } @@ -288,7 +275,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp while (*text) { utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); for (curfont = drw->fonts; curfont; curfont = curfont->next) { - charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + charexists = charexists || wld_font_ensure_char(curfont->wld, utf8codepoint); if (charexists) { if (curfont == usedfont) { utf8strlen += utf8charlen; @@ -320,9 +307,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp ; /* NOP */ if (render) { - ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; - XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], - usedfont->xfont, x, ty, (XftChar8 *)buf, len); + ty = y + (h - usedfont->wld->height) / 2 + usedfont->wld->ascent; + wld_draw_text(drw->renderer, usedfont->wld, drw->scheme[invert ? ColBg : ColFg], + x, ty, buf, len, NULL); } x += ew; w -= ew; @@ -343,7 +330,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp FcCharSetAddChar(fccharset, utf8codepoint); if (!drw->fonts->pattern) { - /* Refer to the comment in xfont_create for more information. */ + /* Refer to the comment in wldfont_create for more information. */ die("the first font in the cache must be loaded from a font string."); } @@ -354,38 +341,37 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); - match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + match = FcFontMatch(NULL, fcpattern, &result); FcCharSetDestroy(fccharset); FcPatternDestroy(fcpattern); if (match) { - usedfont = xfont_create(drw, NULL, match); - if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + usedfont = wldfont_create(drw, NULL, match); + if (usedfont && wld_font_ensure_char(usedfont->wld, utf8codepoint)) { for (curfont = drw->fonts; curfont->next; curfont = curfont->next) ; /* NOP */ curfont->next = usedfont; } else { - xfont_free(usedfont); + wldfont_free(usedfont); usedfont = drw->fonts; } } } } - if (d) - XftDrawDestroy(d); return x + (render ? w : 0); } void -drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +drw_map(Drw *drw, struct wl_surface *surface, int x, int y, unsigned int w, unsigned int h) { if (!drw) return; - XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); - XSync(drw->dpy, False); + wl_surface_damage(surface, x, y, w, h); + wld_flush(drw->renderer); + wld_swap(drw->surface); } unsigned int @@ -399,18 +385,19 @@ drw_fontset_getwidth(Drw *drw, const char *text) void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) { - XGlyphInfo ext; + struct wld_extents ext; if (!font || !text) return; - XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + wld_font_text_extents_n(font->wld, text, len, &ext); if (w) - *w = ext.xOff; + *w = ext.advance; if (h) - *h = font->h; + *h = font->wld->height; } +#if 0 Cur * drw_cur_create(Drw *drw, int shape) { @@ -433,3 +420,4 @@ drw_cur_free(Drw *drw, Cur *cursor) XFreeCursor(drw->dpy, cursor->cursor); free(cursor); } +#endif diff --git a/drw.h b/drw.h index 4c67419..1f1967e 100644 --- a/drw.h +++ b/drw.h @@ -1,34 +1,30 @@ /* See LICENSE file for copyright and license details. */ -typedef struct { - Cursor cursor; -} Cur; +typedef void Cur; typedef struct Fnt { - Display *dpy; - unsigned int h; - XftFont *xfont; + struct wld_font *wld; FcPattern *pattern; struct Fnt *next; } Fnt; enum { ColFg, ColBg }; /* Clr scheme index */ -typedef XftColor Clr; +typedef uint32_t Clr; typedef struct { unsigned int w, h; - Display *dpy; - int screen; - Window root; - Drawable drawable; - GC gc; + struct wl_display *dpy; + struct wld_context *ctx; + struct wld_renderer *renderer; + struct wld_surface *surface; + struct wld_font_context *fontctx; Clr *scheme; Fnt *fonts; } Drw; /* Drawable abstraction */ -Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); -void drw_resize(Drw *drw, unsigned int w, unsigned int h); +Drw *drw_create(struct wl_display *dpy); +void drw_resize(Drw *drw, struct wl_surface *surface, unsigned int w, unsigned int h); void drw_free(Drw *drw); /* Fnt abstraction */ @@ -54,4 +50,4 @@ void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); /* Map functions */ -void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); +void drw_map(Drw *drw, struct wl_surface *surface, int x, int y, unsigned int w, unsigned int h); -- 2.30.1