Mercurial > minori
diff dep/animia/src/win/x11.cc @ 156:cdf79282d647
dep/animia: add VERY early x11 window stuff
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Wed, 15 Nov 2023 18:04:04 -0500 |
parents | |
children | 18c8eb5d1edc |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dep/animia/src/win/x11.cc Wed Nov 15 18:04:04 2023 -0500 @@ -0,0 +1,115 @@ +#include <X11/Xlib.h> + +/* The code for this is very fugly because X11 uses lots of generic type names + (i.e., Window, Display), so I have to use :: when defining vars to distinguish + between Animia's types and X11's types */ + +namespace animia::internal::x11 { + +static bool GetWindowPropertyAsString(::Display* display, ::Window window, const char* atom, std::string& result, ::Atom reqtype = AnyPropertyType) { + int format; + unsigned long leftover_bytes, num_of_items; + ::Atom type; + void* data; + + if (!::XGetWindowProperty(display, root, ::XInternAtom(display, atom, true), 0L, (~0L), false, reqtype, + &type, &format, &num_of_items, &leftover_bytes, &data)) + return false; + + result = std::string(data, num_of_items); + + ::XFree(data); + + return true; +} + +static bool GetWindowPID(::Display* display, ::Window window, pid_t& result) { + int format; + unsigned long leftover_bytes, num_of_items; + ::Atom type; + void* data; + + if (!::XGetWindowProperty(display, root, ::XInternAtom(display, atom, true), 0L, (~0L), false, reqtype, + &type, &format, &num_of_items, &leftover_bytes, &data)) + return false; + + result = static_cast<pid_t>(*(uint32_t*)data); + + ::XFree(data); + + return true; +} + +static bool FetchName(::Display* display, ::Window window, std::string& result) { + /* TODO: Check if XInternAtom created None or not... */ + if (GetWindowPropertyAsString(display, window, "_NET_WM_NAME", result, ::XInternAtom(display, "UTF8_STRING", false))) + return true; + + /* Fallback to XGetWMName() */ + XTextProperty text; + + { + int status = ::XGetWMName(display, window, &text); + if (!status || !text_prop.value || !text_prop.nitems) + return false; + } + + char** list; + + { + int num; + + int status = ::XmbTextPropertyToTextList(display, &text, &list, &num); + if (status < Success || !num || !*list) + return false; + } + + ::XFree(text.value); + + result = *list; + + ::XFreeStringList(list); + + return true; +} + +bool X11WinTools::EnumerateWindows(window_proc_t window_proc) { + auto get_window_property = [&](Display* display, Window window, Atom atom, unsigned long& num_of_items, void*& data) -> int { + int format; + unsigned long leftover_bytes; + ::Atom realtype; + + return ::XGetWindowProperty(display, root, atom, 0L, (~0L), false, AnyPropertyType, + &realtype, &format, &num_of_items, &leftover_bytes, &data); + } + + ::Display* display = ::XOpenDisplay(nullptr); + ::Window root = ::DefaultRootWindow(display); + + unsigned long num_windows; + ::Window* windows = nullptr; + + int status = get_window_property(display, root, ::XInternAtom(display, "_NET_CLIENT_LIST", true), num_windows, (void*)windows); + + if (status < Success) + return false; + + for (long k = 0; k < num_windows; k++) { + const ::Window window = windows[k]; + + Window win; + win.id = (long)windows[k]; + GetWindowPropertyAsString(display, window, "_NET_ACTIVE_WINDOW", win.class_name, ::XInternAtom(display, "STRING", false)); + win.title = FetchName(display, windows[k]); + + Process proc; + GetWindowPID(display, window, proc.pid); + + if (!window_proc(proc, win)) + return false; + } + + return true; +} + +}