Mercurial > minori
view dep/animia/src/win/x11.cc @ 198:bc1ae1810855
dep/animia: switch from using classes to global functions
the old idea was ok, but sort of hackish; this method doesn't use classes
at all, and this way (especially important!) we can do wayland stuff AND x11
at the same time, which wasn't really possible without stupid workarounds in
the other method
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 24 Dec 2023 02:59:42 -0500 |
parents | 0fc126d52de4 |
children | 9f3534f6b8c4 |
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> #include <set> /* 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, ::Atom atom, std::string& result, ::Atom reqtype = AnyPropertyType) { int format; unsigned long leftover_bytes, num_of_items; ::Atom type; unsigned char* data; int status = ::XGetWindowProperty(display, window, atom, 0L, (~0L), False, reqtype, &type, &format, &num_of_items, &leftover_bytes, &data); if (status != Success || !(reqtype == AnyPropertyType || type == reqtype) || !num_of_items) 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 atom = ::XInternAtom(display, "_NET_WM_PID", False), type; unsigned char* data; int status = ::XGetWindowProperty(display, window, atom, 0L, (~0L), False, XA_CARDINAL, &type, &format, &num_of_items, &leftover_bytes, &data); if (status != Success || type != XA_CARDINAL || num_of_items < 1) 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, ::XInternAtom(display, "_NET_WM_NAME", False), result, ::XInternAtom(display, "UTF8_STRING", False))) return true; if (GetWindowPropertyAsString(display, window, ::XInternAtom(display, "WM_NAME", False), result, XA_STRING)) 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; } static bool WalkWindows(::Display* display, std::set<::Window>& children, const std::set<::Window>& windows) { /* This sucks. It takes waaaay too long to finish. * TODO: Look at the code for xwininfo to see what they do. */ if (windows.empty()) return false; for (const ::Window& window : windows) { unsigned int num_children = 0; ::Window* children_arr = nullptr; ::Window root_return; ::Window parent_return; int status = ::XQueryTree(display, window, &root_return, &parent_return, &children_arr, &num_children); if (!status || !children_arr) continue; if (num_children < 1) { ::XFree(children_arr); continue; } for (int i = 0; i < num_children; i++) if (!children.count(children_arr[i])) children.insert(children_arr[i]); ::XFree(children_arr); std::set<::Window> children_children; if (WalkWindows(display, children_children, children)) children.insert(children_children.begin(), children_children.end()); } return true; } bool EnumerateWindows(window_proc_t window_proc) { if (!window_proc) return false; ::Display* display = ::XOpenDisplay(nullptr); if (!display) return false; ::Window root = DefaultRootWindow(display); std::set<::Window> windows; WalkWindows(display, windows, {root}); for (const auto& window : windows) { Window win; win.id = window; { ::XClassHint* hint = ::XAllocClassHint(); if (::XGetClassHint(display, window, hint)) { win.class_name = hint->res_class; ::XFree(hint); } } FetchName(display, window, win.text); Process proc; GetWindowPID(display, window, proc.pid); if (!window_proc(proc, win)) return false; } return true; } }