From dfeb19b0a83b8ce57d28bf94a4f8d129993d1064 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Mon, 12 Jan 2026 23:06:20 +0100 Subject: Initial commit --- src/find_desktop.cc | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/find_desktop.cc (limited to 'src/find_desktop.cc') diff --git a/src/find_desktop.cc b/src/find_desktop.cc new file mode 100644 index 0000000..a3a9330 --- /dev/null +++ b/src/find_desktop.cc @@ -0,0 +1,152 @@ +#include "find_desktop.hh" + +#include "xcb_atoms.hh" +#include "xcb_connection.hh" +#include "xcb_event.hh" +#include "xcb_resource.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +int get_from_e17_using_window(xcb_connection_t* conn, xcb_window_t wnd, + xcb_atom_t e_window_desk) { + if (e_window_desk == XCB_ATOM_NONE) { + return -1; + } + + for (int i = 0; i < 2; ++i) { + auto cookie = + xcb_get_property(conn, 0, wnd, e_window_desk, XCB_ATOM_CARDINAL, 0, 2); + xcb::reply reply( + xcb_get_property_reply(conn, cookie, nullptr)); + + if (reply && reply->format == 32 && + xcb_get_property_value_length(reply.get()) >= 8) { + auto* data = static_cast(xcb_get_property_value(reply.get())); + auto x = data[0]; + auto y = data[1]; + return static_cast((x * 256) + y); + } + + xcb_flush(conn); + struct timespec ts = {.tv_sec = 0, .tv_nsec = 250000000}; // 250ms + nanosleep(&ts, nullptr); + } + return -1; +} + +std::string create_desktop(std::string const& prefix, int desktop, + bool use_prefix) { + std::string ret; + if (use_prefix) { + ret.append(prefix); + ret.push_back('_'); + } + auto const offset = ret.size(); + ret.resize(offset + 10); + auto [ptr, ec] = + std::to_chars(ret.data() + offset, ret.data() + ret.size(), desktop); + if (ec == std::errc()) { + ret.resize(ptr - ret.data()); + } else { + assert(false); + ret.resize(offset); + } + return ret; +} + +} // namespace + +std::optional find_desktop(std::optional display, + bool use_prefix) { + int screen_num = 0; + auto conn = xcb::make_shared_conn(xcb_connect( + display.has_value() ? display.value().c_str() : nullptr, &screen_num)); + if (!conn || xcb_connection_has_error(conn.get())) { + return std::nullopt; + } + + auto atoms = xcb::Atoms::create(conn); + if (!atoms) { + return std::nullopt; + } + + auto* screen = xcb::get_screen(conn.get(), screen_num); + if (!screen) { + return std::nullopt; + } + + xcb_window_t root = screen->root; + + auto net_current_desktop_atom = atoms->get("_NET_CURRENT_DESKTOP"); + auto e_window_desk_atom = atoms->get("__E_WINDOW_DESK"); + + if (!atoms->sync()) { + return std::nullopt; + } + + auto* desktop_env = getenv("DESKTOP"); + if (!desktop_env || strncmp(desktop_env, "Enlightenment-0.17", 18) != 0) { + /* Skip _NET_CURRENT_DESKTOP if we're in e17 */ + /* Try to read the _NET_CURRENT_DESKTOP property */ + auto net_current_desktop = net_current_desktop_atom.get(); + if (net_current_desktop != XCB_ATOM_NONE) { + auto cookie = xcb_get_property(conn.get(), 0, root, net_current_desktop, + XCB_ATOM_CARDINAL, 0, 1); + xcb::reply reply( + xcb_get_property_reply(conn.get(), cookie, nullptr)); + + if (reply && reply->format == 32 && + xcb_get_property_value_length(reply.get()) >= 4) { + auto* data = + static_cast(xcb_get_property_value(reply.get())); + return create_desktop("ewmh", static_cast(data[0]), use_prefix); + } + } + } + + /* Failing that, let's see if our owner knows */ + auto* windowid_env = getenv("WINDOWID"); + if (windowid_env) { + auto* const end = windowid_env + strlen(windowid_env); + unsigned long windowid; + auto [ptr, ec] = std::from_chars(windowid_env, end, windowid); + if (ptr == end && ec == std::errc{}) { + auto ret = get_from_e17_using_window(conn.get(), + static_cast(windowid), + e_window_desk_atom.get()); + if (ret != -1) { + return create_desktop("enlightenment", ret, use_prefix); + } + } + } + + /* Try creating a bogus window then */ + { + auto wnd = xcb::make_unique_wnd(conn); + xcb_create_window(conn.get(), XCB_COPY_FROM_PARENT, wnd->id(), root, 0, 0, + 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, 0, nullptr); + xcb_map_window(conn.get(), wnd->id()); + xcb_flush(conn.get()); + + auto ret = get_from_e17_using_window(conn.get(), wnd->id(), + e_window_desk_atom.get()); + if (ret != -1) { + return create_desktop("enlightenment", ret, use_prefix); + } + } + + /* Don't know what else to do */ + return std::nullopt; +} -- cgit v1.2.3-70-g09d2