Is 2024 a suitable year to start exploring the #XCB API? πŸ˜†

I'm seriously thinking about it. Looks like a nice way to use #X11 and integrate that into your own async/event-driven loop based on traditional #POSIX stuff (like poll or select) πŸ€”

Well, it does show an empty window and handles closing it πŸ™ˆπŸ˜…
https://github.com/Zirias/xmoji
GitHub - Zirias/xmoji: Plain X11 emoji keyboard

Plain X11 emoji keyboard. Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub

@zirias Looks good to me, with just a quick cursive glance over the code.

I'll wait to see how you get on, but there's a couple of things around handling replies from xcb which you could probably add. I'm sure you've noticed this already, but the pattern of:

xcb *cooke_reply = xcb_api_call();
if (cookie_reply == NULL) {
/* Some error. */
}

Is a common pattern. It can get a bit annoying...

@thomasadam Hey, thanks a lot for quick review! I'm completely new to #xcb (only got in touch with it because I wanted to "fake" key-press events for emojis) or "raw" X11 in general... but I like how the API is designed for completely async operation! In this little testing code I'm using my own library I created for networking daemons, but it seems to be a good match and should allow integrating everything into a pselect()-based event loop (offered by that lib). I thought of just adding a queue of xcb-cookies to my X11Adapter class, so it can check for replies whenever the socket gets ready to read... πŸ€”

@zirias Heh. Don't put too much faith in my (rather tired) eyes, but you're welcome.

Yeah -- you should be fine to collate a bunch of cookie-replies together -- XCB is designed to send them whenever, so it's up to you to process them when you see fit -- which is non-blocking my design.

Interestingly, most of the "older" XLib APIs use XCB under-the-hood, so whichever way you look at it, XCB is used all over the place.

@thomasadam Yes, I read it was more or less rewritten on top of xcb as "xlib-xcb", which eventually replaced the old xlib completely. Diving into #X11 now, starting at the "lowest level" (without trying to implement the protocol yourself) seemed appropriate πŸ˜‰

The only "issue" I have is lack of documentation ... there are *some* (incomplete) manpages, there are doxygen-docs (found online or you can directly read the installed headers) which is also incomplete and *very* brief ... and then you can of course use google and hope for the one actually *helpful* stackoverflow result πŸ™ˆπŸ˜„

At least there's a tutorial somewhere explaining the basics.

@zirias Anything I can do to help, just let me know. The canonical source of truth is always going to be the reps, but if you’re funding the man pages, or other β€œofficial documentation” lacking, let me know. I’d like to correct that.
@thomasadam First thing I'll try now is a bit of font rendering, let's see how this turns out. Thanks for the offer, I'll certainly ask questions on here in case I'm totally stuck πŸ™ˆ

@thomasadam Well, seems this would have been rushing it, font rendering only after getting a sane base for windows and widgets πŸ€”

For now, I added a base "Object" for classes that need inheritance with virtual functions (guess that's hard to avoid in GUI code when you want a somewhat "clean" model) and some very basic "Window" base class with a few properties.

This will be a slow project πŸ˜…

Ok, handling #xcb replies completely #async from a "cookie queue" (actually only the #X11 sequence number is relevant) *seems* to work. But only tested with very simple cases so far that don't have a reply πŸ™ˆ

BTW, that's certainly one of the heavily underdocumented areas of xcb πŸ™„

https://github.com/Zirias/xmoji/commit/c6d5e8f754437f0cd39dc52fe3651e89052bfcc4

X11Adapter: Add async queue for xcb replies Β· Zirias/xmoji@c6d5e8f

Test with initial requests for window creation

GitHub

Hehe, my "plain #X11 with #xcb" journey is really starting at square 1.

TIL, "legacy" (ICCCM) X11 window properties use a type STRING which only allows #latin1 encoding. There's a weird thing called COMPOUND_TEXT to work around that which probably isn't worth implementing today. 🀯

Fixed my code to
- Make sure we use a UTF-8 locale
- Convert the window title to Latin1 for setting WM_NAME
- Additionally set the original UTF-8 title in _NET_WM_NAME (of type UTF8_STRING).

Wow, baby steps πŸ˜‚

https://github.com/Zirias/xmoji/commit/3701d56cc76e1cd5688e20aed3539562faf90950

X11Adapter: Conversion to latin1 (for STRING) Β· Zirias/xmoji@3701d56

Handle encoding for X11 STRING properties, init locale and try to make sure we're using UTF-8, set window title in both legacy WM_NAME and UTF-8 _NET_WM_NAME.

GitHub

Next baby step exploring #X11 with #xcb ....

after setting some sane WM_CLASS on my window, my #fvwm3 config doesn't mistakenly set it slightly transparent any more πŸ™ˆ

https://github.com/Zirias/xmoji/commit/33f575fba110a9b0fc830b41a34f744b67c58149

Window: Add window class and type Β· Zirias/xmoji@33f575f

Make sure windows get the WM_CLASS and _NET_WM_TYPE properties

GitHub
Another baby step (and a new dependency): locating a font. Yes, only locating. #X11 #font rendering with just #xcb, #fontconfig and #freetype will take a while 😎

Ok, after experimenting a bit with #fontconfig, seems it has a lot of "helpful" magic to "always give you *some* font". Nice, but that could be whatever. To allow an application-side priority list, I hacked comparing at least the family name of the suggested match, but as a very last resort, just request "sans" and take whatever you get πŸ™ˆ

https://github.com/Zirias/xmoji/blob/8b502a8e0ebc549da9ac3cc71b46fe012e57f81c/src/bin/xmoji/font.c#L47

Now I can create a FT_Face from the result with #freetype. Finding and rendering glyphs to FT_Bitmap seems straight forward, but how would I get that rendered on some #xcb drawable? I found an example using xcb-render-util, but that's "only good for ~252 glyphs" -- huh? 🀨

Anyone have a good example how to do it manually with maybe just xcb-render (without pulling in the next huge lib like cairo)? Maybe @thomasadam ? πŸ˜‰

xmoji/src/bin/xmoji/font.c at 8b502a8e0ebc549da9ac3cc71b46fe012e57f81c Β· Zirias/xmoji

Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub
@zirias More than happy to help. I’m away for the weekend. Please remind me though…
@thomasadam Thanks! I guess I'll explore #harfbuzz, mainly for grapheme-cluster support which is a *must* to display emojis (and trying to do it yourself seems kind of stupid). But then, the problem probably stays the same, how to bring the result to some #xcb drawable ...

@thomasadam It seems to get worse. If I interpret that correctly, the "Noto Color Emoji" font is a bitmap font, with just one (pretty large) size available.

So far, I found no means to scale #bitmap #fonts with #freetype. Is this really not covered? That would certainly be another thing I don't want to implement myself πŸ˜• (cause, yet another case of "re-inventing the wheel").

Digging deeper, it seems "Noto Color Emoji" isn't *really* a "bitmap font" but mostly(?) includes #SVG glyphs. And of course, scalable(!) vector graphics aren't scalable from the freetype perspective (yes, it does make sense, it's even documented you need a separate renderer for these ... would I pull in an indirect dependency on #rust at this point? 🀯)

I feel like maybe giving up and instead do some gfx rendering on the good old #VIC-II of the #C64 πŸ˜‚

For now, accepting facts, I just "completed" my font loading code to select a "best match" fixed size for non-scalable fonts:
https://github.com/Zirias/xmoji/commit/8c4659b7c03bbd3ad15e94aa4c76e7788bd0915d

A next sane step might be to at least try to "shape" some "normal" text (not #emojis) with #harfbuzz and try to render this with #xcb #xrender ... 🀨

Font: Improve loading, select best size Β· Zirias/xmoji@8c4659b

For scalable fonts, select desired size as determined by fontconfig. For "fixed size" fonts, select nearest size, prefering a size that's larger than the desired one.

GitHub

Quickly collecting dependencies meanwhile, this is how it looks like πŸ™„

I did add the first 5 (#fontconfig, #freetype, #harfbuzz, #poser, #xcb) explicitly. Poser is my own lib, it pulls in ssl/crypto for (build-time optional) support of TLS sockets. Fascinating what else I collected here πŸ˜‚

Hell, there's even a C++ runtime? 🀨

Started work on some TextRenderer class/module.

Should in the end handle everything to get an #X11 #pixmap from some #utf8 text. For now, just runs #harfbuzz shaping and calculates the resulting pixel size in a background thread.

I have no idea whether my calculations are really correct. But at least, the result for a "Hello, World!" text looks somewhat plausible πŸ˜…

https://github.com/Zirias/xmoji/commit/439d0dfee46a4f40a671634a0f18d9c9accbb543

TextRenderer: WIP, render some text Β· Zirias/xmoji@439d0df

For now, asynchronously shape given text with harfbuzz and calculate pixel size of the result.

GitHub

Wow, I was stalled for days now because I couldn't figure out why my queue of outstanding #X11 replies always quickly overflowed.

Turns out one factor was a simple coding error in text rendering test code, leading to repeatedly issuing the same requests πŸ™ˆ.

But I didn't find that because processing also stalled. Turns out integrating #xcb correctly with your own event loop is somewhat tricky 🀯.

I guess I figured it out now, finally πŸ₯³. And for the first time ever, I found a good use for #C11's _Generic() πŸ˜‚. Screenshot is lots of debugging output, the batch of confirmed requests on the bottom is from requests uploading #glyphs, and trying to use some #xrender stuff with them. Now for the hard part: My window stays plain white ... πŸ˜’

Finally, some *visible* result from my #X11 / #xcb experimenting with #freetype and #harfbuzz for font rendering. πŸ₯³

https://github.com/Zirias/xmoji/commit/80e953a98048419124f0a2ef72e9eaefb8812789

There are issues to fix:

* Sometimes, it renders nothing visible. I'm not sure where this indeterminism could come from 🫀
* xcb/render.h offers a struct for color with fields for red, green, bue and alpha (in this order). If I use {0,0,0,1} here, I see nothing on a white background. {1,0,0,0} gives me black text. πŸ€” Now either I'm doing something *completely* wrong, or there's some confusion somewhere whether colors are ARGB or RGBA format. Huh?

There's also an issue that probably doesn't have a fix. #harfbuzz shaping outputs rendering positions in fractional pixels. I *think* XRender only accepts whole pixels, so I have to round the position for every single glyph. I wonder whether this is a reason for many to use #cairo for rendering?

@thomasadam if you can shed some light on one of these issues, that would be awesome, but I guess I'm not exactly "stuck" here, need to do more research πŸ˜…

TextRenderer: Make something render Β· Zirias/xmoji@80e953a

This has still several bugs, but most of the time, it renders "helloworld" using freetype, harfbuzz and XRender.

GitHub

@thomasadam Ha! Adding some color (lol) helped to identify and fix the issues πŸ˜†

There were two different ones. First, the color used was non-deterministic. Tracked that down to sometimes picking the wrong XRender picture format 🀦 (turns out there can be more than one 32bpp format available, you have to check the shift values of the color channels to make sure you got ARGB) ... now the xcb_render_color_t works as expected.

Second, sometimes it rendered nothing at all. Tracked that one down to freeing the rendering data too early, the request has just a pointer and might still be queued by #xcb πŸ™ˆ

Ok, "simple" text rendering: done. βœ…

@thomasadam I start wondering whether "shaping" artifacts from "rounded" #glyph positions can be avoided at all? πŸ€”

If I understand that correctly, you always rasterize one glyph at a time with #freetype. So, it starts at a "whole" pixel position, right? Do I overlook anything?

@zirias Yes, that's correct. Do you have an example of what you're trying?

@thomasadam I'm using #harfbuzz to "shape" my text. It's giving me "advance" values in 1/64th pixels. To have that shaped text rendered "perfectly", you'd have to position the glyphs in that high resolution and rasterize as a whole I guess. Seems that's just not possible with #freetype though.

So, I'm using the info from harfbuzz to position individual glyphs at the nearest whole-pixel position instead. 🀷

Just wondering whether I overlooked something, but I guess that's indeed the way to go...

https://github.com/Zirias/xmoji/blob/1fb2e5e01558a6dd72cbf0048ba4389aaa48d180/src/bin/xmoji/textrenderer.c#L159

xmoji/src/bin/xmoji/textrenderer.c at 1fb2e5e01558a6dd72cbf0048ba4389aaa48d180 Β· Zirias/xmoji

Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub

@thomasadam Taking it as it is right now (cause I GUESS there's no way to "do better", give me a hint if I'm wrong) and moving on:

I need #widgets now!

This text rendering is currently hardcoded into my "window" which is *meant* to model just some "generic" #X11 window. It should instead contain some generic widget (probably some tree of these) to show "whatever". In some sense, this would be a (tiny) "toolkit" for #xcb then ...

Years ago, I experimented with raw #win32 (but using microsoft's "common controls" lib), and there, every "control" was actually a window. From what I understood so far, you don't do that with #X11, but instead draw on your actual window surface using offset positions ... is this correct? πŸ€”

@zirias Without seeing the design of this’s, you should remember that there’s a difference between providing drawing primitives (widgets), and the behaviour of the window itself which behaves as widgets should.

So, for example β€” by all means provide pre-defined widgets with whatever meds to be in them. If you’re going down the route of providing your own primitives, Fvwm{Form,Script} will be useful to you here. Or you could use a higher-level library like Xt.

As for window behaviour, let’s talk separately about that…

@thomasadam I understand only parts of this I have to admit πŸ˜•

Currently working on "optimizing" my interfacing with #xcb first, I think I finally understood how it works (requests, replies, errors) and now I try to use that fully asynchronously with the least possible overhead (on the socket) while automatically injecting a dummy "sync" request when it's *really* necessary ... commit following soon 😏

But then, yep, widgets is what I will need. I'm thinking about completely ignoring all #X11 drawing primitives and just use #XRender for everything, hoping that's a somewhat sane thing to do πŸ˜…

@thomasadam So, I guess *this* is done:
https://github.com/Zirias/xmoji/commit/cd0a2db4f871f3d6a44dcfce6d0c76a4df93c850

The core of my fully async #xcb wrapping API are two macros I finally documented (necessary because otherwise, I'll forget myself, and some _Generic() magic isn't exactly readable πŸ™ˆ):
https://github.com/Zirias/xmoji/blob/cd0a2db4f871f3d6a44dcfce6d0c76a4df93c850/src/bin/xmoji/x11adapter.h#L35

It does what I want, requests are minimized, this debug log shows the result after triggering redraws by resizing the window and minimizing/restoring it πŸ₯³

(No excuse left now to tackle a widgets concept πŸ˜…)

X11Adapter: Rework async X11 handling Β· Zirias/xmoji@cd0a2db

Add CHECK() macro for only checking for errors. Provide overloads for either calling a specific callback or just log something and optionally fire a generic event on a given id. Document usage of ...

GitHub

@zirias Again, just eyeballing this far too quickly than I’d like to right now, things looks good to me.

Will look thoroughly when I’ve more time.

@thomasadam I might be sidetracked again: I guess I found a viable solution for my "glyph positioning issue".

It seems #freetype can use an offset when rasterizing a glyph:
https://freetype.org/freetype2/docs/reference/ft2-outline_processing.html#ft_outline_translate
Should be possible to use that for rasterizing 4 variants of the same glyph, shifted by quarter pixels.

A truetype font will have a maximum of 2^16 glyphs, an #XRender glyphset can contain up to 2^32 glyphs ... just adding two bits here for somewhat sane render quality seems like a good idea.

I'll try to implement that first before testing something else πŸ™ƒ

Outline Processing - FreeType-2.13.2 API Reference

API Reference Documentation for FreeType-2.13.2

@thomasadam Awesome, this is the solution πŸ₯³: Reserve two bits of the #glyph id in the #XRender glyphset to indicate one of 4 horizontal shift positions for the same glyph. Result looks nice IMHO.

Screenshots:
1. New rendering
2. Old rendering 8x zoom
3. New rendering 8x zoom

https://github.com/Zirias/xmoji/commit/bbc9cd2b5baa79d5a948a1169e1384a0eba5d793

Font/TextRenderer: X positioning to quarter pixels Β· Zirias/xmoji@bbc9cd2

Add two more bits to glyphids to allow 4 variants of the same glyph for 4 different X positions, so the positions obtained from harfbuzz shaping can be approximated a lot better.

GitHub

@thomasadam Made the subpixel resolution configurable.

https://github.com/Zirias/xmoji/commit/8b0f0c8cdc52452afa63de9bdf439e53940d0223

Here's a render test with all possible values (0 to 6 bits subpixel precision).

Only whole pixels is barely acceptable, the kerning is just broken (see the huge gap between the two lowercase L). Two bits for subpixels already looks pretty good, more don't seem to improve the result here further although I can spot a minimal difference up to 4 bits πŸ™‚. Seems a "sane" value should be 2 or 3 bits for this.

#XRender #xcb #text #rendering #freetype #harfbuzz

Font/TextRenderer: Configurable subpixel precision Β· Zirias/xmoji@8b0f0c8

* Add Font constructor parameter to specify number of subpixel bits in the range 0-6 * Calculate valid XRender glyphid range from this and the number of glyphs in the font * Use this info in Te...

GitHub

@thomasadam Looking at my #xcb/#x11 code so far, I have one doubt: Many X11 requests have uintX_t (e.g. uint32_t, or, in "X11 lingo", CARD32) fields. There are even request payloads (e.g. for uploading glyphs) containing multi-byte integers.

What about #endianness? 🀨

My "just search the web" attempts so far only told me that there is a "foreign endian client" mechanism in X11? 🧐 But it was removed? πŸ˜–

Is there something like negotiation of endianness in #X11? Or should I rely on #xcb to handle this (which seems kind of implausible at least for payloads)? Or should I do something, and if yes, what? ❓

Another tiny step forward with plain #X11 using #xcb ... my experimentation code now has a first super-simple #widget, a text label. πŸ₯³

Also added a parent-child structure, an automatically inherited color set and automatic minimum size calculation!

@thomasadam So far, work on #xcb-based #widgets seems pretty straight-forward.

My widget base class already does a few things, like maintain size and minimum size, padding, alignment, an inherited color-set, optionally draw a background, etc....

Only one concrete widget so far, a simple text label (at least it accepts multi-line text and calculates the line positions from the line height #freetype reports).

Here's the code constructing this super-simple window content:
https://github.com/Zirias/xmoji/blob/852788c97965bd97ea4e7e2e4461deb686ec7b4b/src/bin/xmoji/xmoji.c#L36

xmoji/src/bin/xmoji/xmoji.c at 852788c97965bd97ea4e7e2e4461deb686ec7b4b Β· Zirias/xmoji

Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub

@thomasadam Let's see what we have so far (#X11 properties). Looks mostly sane I'd say?

But what's _NET_WM_ICON_VISIBLE_NAME, who is setting that, and how does it end up so garbled? 😦

For the window name, so far I only set _NET_WM_NAME (utf8) and WM_NAME (converted to latin1)....

@zirias Do you have an icon name specified for the window? Is WM_ICON_NAME set? If you do -- certainly in fvwm's case -- it will also set _NET_WM_ICON_VISIBLE_NAME to match _NET_WM_VISIBLE_NAME
@thomasadam No, should I set an icon name? I'll try that and see whether something changes πŸ˜‰

@thomasadam Yes, when I set an icon name (WM_ICON_NAME and _NET_WM_ICON_NAME), the property just reflects that.

So I guess in absence of an icon name, fvwm tries to use the window name for it and reflects that in _NET_WM_ICON_VISIBLE_NAME?

Could the garbled encoding be a bug in fvwm? πŸ€”

@thomasadam And another "interesting" issue that only happens sometimes ... I just added lots of debug output to analyze why my Window sometimes draws when it should close, and here's the proof: that's triggered by a bogus(?) expose event (that's only sometimes received). The preceding ClientMessage is the WM_DESTROY one. Any idea what could cause this and whether I can somehow stop it from happening? 🧐

A workaround should be simple though, just stop processing expose events for a window that already requested unmapping πŸ™„

#x11 #xcb #programming

@thomasadam Adventures in #X11 #programming using #xcb ... I think I discovered some strange (and, undocumented?) behavior in #Xorg.

Getting more seemingly(!) "stray" Expose events, I finally discovered what's happening. I already decoupled my drawing logic from handling Expose, and instead maintain information in a widget whether it's visible and invalidated (with invalidation triggered by whatever, e.g. an Expose event). Only after processing a batch of input from the X server, I check whether a widget is both visible and invalidated, and if yes, draw it. So far a common pattern to avoid excessive drawing.

Now, setting the "root" widget (the window) visible as soon as a MapNotify is received, this *could* lead to start drawing before receiving the first Expose. Drawing still works perfectly fine, but this somehow delays the Expose event until something else "happens" to the window (like moving it), then you suddenly receive this Expose ... 🀯

Solution: Only set the window "visble" after the first Expose event is received...

I guess it would be impossible to trigger this with #Xlib because its API makes you wait for the response to every request... πŸ˜‰

@zirias Yeah. That’s probably not the best approach.

Not sure if you’d be up for it, but I’d be more than happy to spend some time with you on IRC or Jitsi to go through this with you, if that’s helpful?

@thomasadam Thanks, I just asked over there (libera) πŸ˜‰

Meanwhile it *seems* to all work, so the next "big thing" would be to find a way to #render #SVG (and maybe #PNG) #glyphs for "color emojis". I hope to avoid librsvg for that (would pull in rust and cairo ...), so, will test alternatives...

Weird, I remember reading something somewhere on the noto fonts github that seemed to suggest the emoji font used SVG graphics. But peeking into freetype's face and glyph structures with lldb, it looks more like it's plain RGBA bitmap data ...

Well then, just need to figure out a good way to scale that.

I wonder whether it's possible to do #XRender #CompositeGlyphs requests with a scaling transformation applied? This would certainly be the simplest solution.

Any #X11 or #xcb experts here? πŸ˜…

Had an idea, pure genius πŸ™ˆ: Just check how #Xft is doing it.

Well, turns out it's literally "just doing it":
https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/master/src/xftglyphs.c?ref_type=heads#L327

Maybe I should just do it ... πŸ˜…

#X11 #xcb #XRender #scaling #bitmap #font

src/xftglyphs.c Β· master Β· xorg / lib / libXft Β· GitLab

X FreeType library

GitLab

Rendering a color #glyph with #XRender was the first issue, finally solved. It's surprisingly complicated, because with XRender, a glyph is always an alpha mask, and if it has 4 channels, the actual alpha channel is ignored and the color channels are interpreted as per-component alpha.

To get a sane rendering, I had to create two(!) glyphsets for colorfonts, one ARGB, one alpha only. First render the ARGB one to a temporary pixmap. Then use this pixmap as the source for rendering the alpha glyphset to the real target. Oh, wow πŸ˜…

Now, time to improve scaling, just did a stupid "nearest neighbor" for the first poc ... (screenshot looks good because it's unscaled)

Replaced the super-stupid "nearest neighbor" with some still pretty naive averaging, and yes, that's slightly better, but I guess I won't be happy with that ...

probably time to dig deeper into "good" #scaling (#resampling) algorithms

Aha! A simple filter matrix improves it a lot:
https://github.com/Zirias/xmoji/commit/79aab888be379303ad8cafdd27f34f91b276275f

I guess that'll do for my purposes. Far from perfect, but IMHO acceptable πŸ˜…

Font: Use filter matrix for downscaling Β· Zirias/xmoji@79aab88

Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub

played a bit more with the shape of my filter matrix and now I'm really happy πŸ₯³

rendering a scaled color #bitmap font with "pure" #X11 (with #XRender) using #xcb: done! βœ…

Code for testing emoji rendering ... containing emojis ... naturally! 😁

Coding in C is still the most fun.

@thomasadam I guess I meanwhile solved rendering color emoji fonts, both for SVG and bitmap (PNG) glyphs 😎

Still wondering what you meant ... ist it wrong to always wait for the first expose event before starting to draw?

Rarely (really *very* rarely, like once every 50 times), I now end up with an undrawn window which draws as soon as I move it, so probably, something *is* wrong πŸ˜•

Adventures with #X11 #programming using #xcb: I now have to admit it's *really* hard to *correctly* integrate xcb with a typical generic event loop working on file descriptors (e.g. with #select or #poll). My issue of an occassionally undrawn window was probably caused by not getting that correct.

Xcb more or less enforces its own asynchronous model, getting a "cookie" for each request and using that later to check for the reply. This works great if talking to the X server is all you do, but otherwise, it's a pain. Xcb also demuxes events from replies, and while there's a function to check only for *queued* events, there's no such function for replies, so checking for them could always trigger another read from the socket, possibly queueing new events. 🀯

Many projects resort to dedicating a thread to xcb and using its blocking API from there to solve this issue. I think integrating into a generic event loop is still *possible* though, and this is what I finally came up with (commented implementation because it's just too complex):
https://github.com/Zirias/xmoji/blob/d5fcf301c0cb65b5a33e1310b298c01bcd682f47/src/bin/xmoji/x11adapter.c#L148

If you're an xcb expert and spot an error there, please let me know πŸ˜‚

This code requires two things to work reliably:

- Never ever use one of xcb's reply functions, instead use the AWAIT() macro to get a callback when the reply arrives
- Never use an xcb wait_for or poll_for function, if error-handling for a request is needed, use one of the overloads of CHECK()

xmoji/src/bin/xmoji/x11adapter.c at d5fcf301c0cb65b5a33e1310b298c01bcd682f47 Β· Zirias/xmoji

Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub

Integrating #xcb into your own event-loop, continued …

Turns out all of this was still wrong. Sure, I fixed locking up (because of unnoticed queued events), but broke mapping errors to requests. 🀯 Didn't notice for a while because I didn't have any errors in my #X11 requests any more. πŸ™„

Trying to fix *this*, I instead broke receiving actual replies first. 🀦

I finally understood: xcb_poll_for_reply() returns true as soon as xcb considers the request asked for "completed", which is implicitly the case once a reply or an error for a *later* request arrives. But for "unchecked" requests, it will never give you the error, so you *have* to check events to find it. Now, checking request 2, you might have both a reply for request 7 and an error for (unchecked) request 12 queued. Checking events, you'll find the latter. The only reliable solution, so you neither miss the reply 7 nor the error 12: store that error locally and use it later when you actually check request 12.

Fixed, hopefully for the last time now:
https://github.com/Zirias/xmoji/blob/d7a975d1f15b3e7e5aafab9b04f93cf445b858b7/src/bin/xmoji/x11adapter.c#L362

xmoji/src/bin/xmoji/x11adapter.c at d7a975d1f15b3e7e5aafab9b04f93cf445b858b7 Β· Zirias/xmoji

Contribute to Zirias/xmoji development by creating an account on GitHub.

GitHub

@thomasadam Looks like a bug to me. I'm now setting both _NET_WM_NAME and _NET_WM_ICON_NAME to the same utf8 string (with one emoji and some non-asciii characters that are in latin1), plus WM_NAME and WM_ICON_NAME to the same string, but converted to latin1. Here's what I get: _NET_WM_VISIBLE_NAME is correct, _NET_WM_ICON_VISIBLE_NAME is garbled, it looks like utf8 interpreted as latin1 and then converted to utf8 again. The display in FvwmIconMan is correct though... so I'm not sure it's a bug *in #fvwm*, but it is a bug πŸ˜‰

Putting this on my backlog of things to analyze some day πŸ˜