Mercurial > minori
view dep/animia/src/win/x11.cc @ 157:18c8eb5d1edc
x11: make it work
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Thu, 16 Nov 2023 16:51:34 -0500 |
parents | cdf79282d647 |
children | 80d6b28eb29f |
line wrap: on
line source
#include "animia/win/x11.h" #include "animia/win.h" #include "animia.h" #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> // XA_* #include <cstdint> #include <string> /* 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 { /* should return UTF8_STRING or STRING */ 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; unsigned char* data; if (!::XGetWindowProperty(display, window, ::XInternAtom(display, atom, False), 0L, (~0L), False, reqtype, &type, &format, &num_of_items, &leftover_bytes, &data)) return false; result = std::string((char*)data, num_of_items); ::XFree(data); return true; } /* this should return CARDINAL, a 32-bit integer */ static bool GetWindowPID(::Display* display, ::Window window, pid_t& result) { int format; unsigned long leftover_bytes, num_of_items; ::Atom reqtype = XA_CARDINAL, atom = ::XInternAtom(display, "_NET_WM_PID", False), type; unsigned char* data; /* TODO: check the type for this */ if (!::XGetWindowProperty(display, window, atom, 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.value || !text.nitems) return false; } char** list; { int count; int status = ::XmbTextPropertyToTextList(display, &text, &list, &count); if (status < Success || !count || !*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, unsigned char** data) -> int { int format; unsigned long leftover_bytes; ::Atom realtype; return ::XGetWindowProperty(display, window, 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, (unsigned char**)&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]; { ::XClassHint* hint = ::XAllocClassHint(); if (::XGetClassHint(display, window, hint)) { win.class_name = hint->res_class; ::XFree(hint); } } FetchName(display, windows[k], win.text); Process proc; GetWindowPID(display, window, proc.pid); if (!window_proc(proc, win)) return false; } return true; } }