registration pending

  • Ask me anything
  • Random
  • Archive
  • RSS

registration pending

Newer
Older
  • 2012:222 - 04:41:47.195:

    X Window Properties: one small part of the X11 ecosystem (which is about this bad throughout)

    Let’s say you want to write a program that uses X11.

    Okay, sorry to insult your intelligence. Let’s say you’re only a damned fool, and you just want to ask X a teensy bit about some /other/ program that uses X substantially.

    So you want to look up some information about a window; let’s say we want to learn what PID a window claims to be associated with, if any. How that’s done is specified in the EWMH, which uses X’s capabilities (namely window properties, a kind of key-value store scoped to a given window) to let programmers tag windows with such data.

    Sounds fair enough at this point; it’s all very sane at this level of description. Now we get into the ugly bits. A PID is a simple integer, right? So can we store just an integer in this key-value store, given that we’re writing C (a language that lacks greatly in the domain of genericity)? The designers of this key-value store would presumably allow for something more flexible than just plain integers, right? So how do we get a simple integer value out in a type-safe manner?

    Enter int XGetWindowProperty(Display *display, Window w, Atom property, long long_offset, long long_length, Bool delete, Atom req_type, Atom *actual_type_return, int *actual_format_return, unsigned long *nitems_return, unsigned long *bytes_after_return, unsigned char **prop_return);

    Fuuuuuuuuuuuuuuuuuuuck.

    That’s nasty.

    It turns out, XGetWindowProperty is a function that likes to act really low-level. Beyond the obvious parameters, it takes an offset (in 4-byte units) at which it starts reading primitive values, a count (in 4-byte units) of data units to be retrieved, a boolean asking whether to delete the whole property after reading this data, and then some Atoms and ints for what we think the type and ‘format’ are and then return pointers for what they actually are, followed by some return pointers for how many bytes past the end of our selected range are left in the property and how many primitives (in units that depend on the particular type of value stored in the property) are stored, total.

    I’ll address the issues with the function in no particular order:

    First, we’re only able to query primitive elements of the property, and we’re only able to query a contiguous, homogeneous set of those. That’s not really an improvement from being able to query only one primitive (or all of them) at once, and the added arguments only add more complication to this 12-argument function call.

    The offset argument is in four-byte units. Why? We already know that the format of our primitive values might be 8, 16, or 32, so why assume we don’t need finer-grained spacing? This is stupid. The same question arises for the count, which is again measured in units of the wrong granularity.

    (Though it may be somewhat surprising to have it, the bool parameter is fine; it lets us avoid a race condition where two clients could read a ‘consumable’ property that’s being used as a message. Shame X has other race conditions all over.)

    What the ‘type’ parameter means is difficult to discern; the only mentioned valid value in the documentation is AnyPropType. A dig through various sources leads us to /usr/include/X11/XAtom.h, where we see that a type is actually a (usually reserved, i.e. declared in a header rather than dynamically registered) Atom representing a type! The most common values are some proper subset of those defined in XAtom.h; exactly which are used by applications I don’t know, and an application can legally use any registered atom as a property type. It seems best to pass AnyPropType when querying, as the passed type has no effect on what the function does.

    Because the actual type and format are returned by the server, we know that the server stores that information. So why does it ask our opinion when calling XGetWindowProperty, only to discard it and inform us of the truth? Just to keep us on our toes? There aren’t any guarantees enforced upon certain types to ensure that complex properties (like the ICCCM’s WM_HINTS, which consists of 3 32-bit ints, a pixmap id, a window id, two more 32-bit ints, and another pixmap id) have the right number or size of fields. At best, the type is just a hint to clients that can’t discern the type from the property name but that do the same type under a different property name. The lack of expressiveness in the way types are specified means that instead of any more sophisticated handing, XGetWindowProperty has to make do with conveying back the only information it knows about the actual contents of the property: how big it is. For some reason it does this twice: In bytes in bytes_after_return, but that only returns the size of the portion of the property /after/ the chunk requested in 4-byte increments from a 4-byte offset In units of the stored format (bit width) of the property’s fields (i.e. actual_format_return, not the guess we passed) in nitems_return.

    A single, simple, int* size_return would be too easy.

    An expressive system might have an actual XPropType type, which could be anything from a tree of combinators (struct, array) and primitive leaves (atom, window, pixmap, int8/int16/int32) to a shorthand string like “aiss” for {Atom, Integer, String, String} (akin to what dbus does). This would allow for more useful ad-hoc applications of window properties for IPC, and would avoid more errors due to conflicting expectations of clients. We could design an interface like this: int XGetWindowProperty(Display *display, Window w, Atom property, Bool delete, XPropType* type_return, void** prop_return);

    We cut the argument count in half. We maintain the ability to delete a property upon read, and we can query an entire property without knowing its type beforehand, e.g. as xprop might like to do. At present xprop lets users specify a string like “32a” to describe the type of a property for whose type xprop doesn’t have a hard-coded decoder, but real-world formats get more complex: the EWMH specifies _NET_WORKAREA, for example which has a type of “CARDINAL[][4]/32”, meaning “an array of 4-entry arrays of 32-bit integers”. We /could/ take the current approach of flattening everything, and if we pass the full format of the datatype a serialization step can do just that. And with that comprehensive type information stored we can deserialize on the other side and everything is magical.

    Or we could only allow for users to store primitives of an enumerated type in a simple key-value store on a window; higher-level organization could be done with multiple properties. That would also be an improvement from the current system.

    But we didn’t want to waste time fixing X to have some coherent way to deal with data formats in X properties; we wanted to retrieve a PID!

    By now I hope we’ve realized it’s easier to screen-scrape the output of some other program.

    Actual code which will perform this task is:

    int* pid; long dummy; XGetWindowProperty(display, window, XInternAtom(display, "_NET_WM_PID", 0), 0, 1, False, AnyPropertyType, &dummy, &dummy, &dummy, &dummy, (unsigned char**)&pid);

    …which stores the pid in *pid. What a beauty.

    #the provably broken window server #hacking #text #long #fuck that! #linux

    with 3 notes

    Source:

    1. c1qfxugcgy0 likes this
    2. eccentric-nucleus said: i’m real glad i stick to video games right now
    3. eccentric-nucleus likes this
    4. foldingcookie posted this
  • eccentric-nucleus
  • uenostation54
  • groans
  • palmers-medic
  • colossalclit
  • antinegationism
  • zuven
  • sexpigeon
  • deafilion
  • boundup
  • circuit-city
  • puppygamer
  • radianthour
  • inky
  • thingsthatarentbread
  • byebyedaruma
  • insufficientlyadvanced
  • kreayshawn
  • pndbrnd
  • tunicate
  • aidosaur
  • herearesomecomputerthings
  • pol102
  • mesmorino
  • itslef
  • thingsfittingperfectlyintothings
  • beatsnpieces
  • xliimusic
  • kontraptionist
  • larkles
  • plainflavored
  • molochwalk
  • rohanjay
  • staff
  • sayved
  • skullpanda
  • gransquall
  • absolutefucker
  • ezyang
  • doiteverydayfuckyolo
  • generalelectric
  • jetpackexhaust
  • musicmakesmeplane
  • cx-cv
  • bringtheawesome
  • ducksink
  • c1qfxugcgy0
  • butt-stallion-says-hello
  • nazigold
  • jewishfish
  • johnholdun
  • lisahanawalt
  • shiroi-kamaitachi
  • hoodinternet
  • mainframed767
  • abad1dea
  • fogus
  • gallopingoff
  • thecatscan
  • tremphantasma
  • programmingisterrible
  • dsyfo
  • i-i-i-ellen
  • imellon
  • thisweeadventure
  • cookingcircle
  • breadboxing
  • lichray
  • engineering
  • oil-spiller
  • mozillamemes
  • misattributions
  • webkitmemes
  • segfault
  • gabetwee
  • hackedy
  • imagechina
  • irlgoat
  • conqueringanimalsound
  • toadstone
  • adrusi
  • programmablegatorade
  • execrablefrippery
  • groovemonsters
  • shinolajla
  • az-mulog
  • shii
  • ronpaulfuneralcity
  • brrian
  • berkus
  • glitch-release
  • danyet
  • gainfulunemployment
  • insomniac-isotope
  • ubertorso
  • heathermakesmovies
  • tap-lang
  • yodadodo
  • accessmaincomputerfile
  • shameister
  • threebytesfull

Modified Field Notes theme originally by Manasto Jones.