xcbOrg/Window: Destroy connections when no longer in use

This commit is contained in:
2025-07-25 01:21:26 -04:00
parent a17c940377
commit 270437fdd4
4 changed files with 61 additions and 12 deletions
+30 -2
View File
@@ -73,6 +73,18 @@ size_t ConnectionManager::getConnectionCount()
return connections.size(); return connections.size();
} }
/**
* @brief Remove a specific connection from the manager
* @param id Connection identifier to remove
*/
void ConnectionManager::removeConnection(const ConnectionIdentifier& id)
{
auto it = connections.find(id);
if (it != connections.end()) {
connections.erase(it);
}
}
namespace window_search { namespace window_search {
struct XcbReplyDeleter { struct XcbReplyDeleter {
@@ -83,14 +95,14 @@ struct XcbReplyDeleter {
xcb_window_t findById( xcb_window_t findById(
xcb_connection_t* conn, xcb_window_t root, uint32_t targetId) xcb_connection_t* conn, xcb_window_t root, uint32_t targetId)
{ {
if (root == targetId) return root;
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root); xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply( std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
xcb_query_tree_reply(conn, cookie, nullptr)); xcb_query_tree_reply(conn, cookie, nullptr));
if (!reply) return 0; if (!reply) return 0;
if (root == targetId) return root;
xcb_window_t* children = xcb_query_tree_children(reply.get()); xcb_window_t* children = xcb_query_tree_children(reply.get());
int num_children = xcb_query_tree_children_length(reply.get()); int num_children = xcb_query_tree_children_length(reply.get());
@@ -262,3 +274,19 @@ xcb_window_t xcb_xorg_find_window_by_name(void* conn, xcb_window_t root,
connection->getConnection(), root, targetName, outWindowName, connection->getConnection(), root, targetName, outWindowName,
matchType); matchType);
} }
/**
* @brief Dereference a connection (decrements ref count and closes if zero)
* @param conn Shared pointer to the connection to dereference
*/
extern "C" dereference_connection_fn xcb_xorg_dereference_connection;
void xcb_xorg_dereference_connection(std::shared_ptr<xcb_xorg::XcbConnection> conn)
{
if (!conn) return;
int newRefCount = conn->decrementRefCount();
// Remove from connection manager if ref count reaches zero
if (newRefCount <= 0) {
xcb_xorg::ConnectionManager::removeConnection(conn->getIdentifier());
}
}
+8
View File
@@ -126,6 +126,12 @@ public:
*/ */
static size_t getConnectionCount(); static size_t getConnectionCount();
/**
* @brief Remove a specific connection from the manager
* @param id Connection identifier to remove
*/
static void removeConnection(const ConnectionIdentifier& id);
private: private:
static std::map<ConnectionIdentifier, std::shared_ptr<XcbConnection>> connections; static std::map<ConnectionIdentifier, std::shared_ptr<XcbConnection>> connections;
}; };
@@ -167,6 +173,8 @@ xcb_window_t findByName(xcb_connection_t* conn, xcb_window_t root,
typedef std::shared_ptr<xcb_xorg::XcbConnection> get_or_create_connection_fn( typedef std::shared_ptr<xcb_xorg::XcbConnection> get_or_create_connection_fn(
int display, int screen); int display, int screen);
typedef void cleanup_connections_fn(); typedef void cleanup_connections_fn();
typedef void dereference_connection_fn(
std::shared_ptr<xcb_xorg::XcbConnection> conn);
typedef xcb_window_t find_window_by_id_fn( typedef xcb_window_t find_window_by_id_fn(
void* conn, xcb_window_t root, uint32_t targetId); void* conn, xcb_window_t root, uint32_t targetId);
typedef xcb_window_t find_window_by_name_fn(void* conn, xcb_window_t root, typedef xcb_window_t find_window_by_name_fn(void* conn, xcb_window_t root,
+20 -7
View File
@@ -18,6 +18,7 @@ struct XcbXorgDllState
{ {
get_or_create_connection_fn* getOrCreateConnection = nullptr; get_or_create_connection_fn* getOrCreateConnection = nullptr;
cleanup_connections_fn* cleanupConnections = nullptr; cleanup_connections_fn* cleanupConnections = nullptr;
dereference_connection_fn* dereferenceConnection = nullptr;
find_window_by_id_fn* findWindowById = nullptr; find_window_by_id_fn* findWindowById = nullptr;
find_window_by_name_fn* findWindowByName = nullptr; find_window_by_name_fn* findWindowByName = nullptr;
} fns; } fns;
@@ -54,11 +55,12 @@ std::string WindowSelector::stringify() const
} }
AttachedWindow::AttachedWindow(const smo::device::SenseDeviceSpec& spec) AttachedWindow::AttachedWindow(const smo::device::SenseDeviceSpec& spec)
: deviceSpec(spec), xcbConnection(nullptr) : deviceSpec(spec)
{ {
// Validate required function pointers are available // Validate required function pointers are available
if (!xcbXorg.fns.getOrCreateConnection || if (!xcbXorg.fns.getOrCreateConnection ||
!xcbXorg.fns.findWindowById || !xcbXorg.fns.findWindowByName) !xcbXorg.fns.findWindowById || !xcbXorg.fns.findWindowByName
|| !xcbXorg.fns.dereferenceConnection)
{ {
throw std::runtime_error("xcbWindow:" + std::string(__func__) + throw std::runtime_error("xcbWindow:" + std::string(__func__) +
": Required xcbXorg function pointers not available"); ": Required xcbXorg function pointers not available");
@@ -73,7 +75,7 @@ AttachedWindow::AttachedWindow(const smo::device::SenseDeviceSpec& spec)
(*xcbXorg.fns.getOrCreateConnection)( (*xcbXorg.fns.getOrCreateConnection)(
windowSelector.display, windowSelector.screen); windowSelector.display, windowSelector.screen);
xcbConnection = conn.get(); xcbConnectionShared = conn;
// Find the target window // Find the target window
xcb_window_t foundWindow = 0; xcb_window_t foundWindow = 0;
@@ -83,13 +85,13 @@ AttachedWindow::AttachedWindow(const smo::device::SenseDeviceSpec& spec)
if (windowSelector.matchType == xcb_xorg::window_search::MatchType::ID) if (windowSelector.matchType == xcb_xorg::window_search::MatchType::ID)
{ {
foundWindow = (*xcbXorg.fns.findWindowById)( foundWindow = (*xcbXorg.fns.findWindowById)(
xcbConnection, screen->root, conn.get(), screen->root,
windowSelector.windowId); windowSelector.windowId);
} }
else else
{ {
foundWindow = (*xcbXorg.fns.findWindowByName)( foundWindow = (*xcbXorg.fns.findWindowByName)(
xcbConnection, screen->root, conn.get(), screen->root,
windowSelector.windowName, actualWindowName, windowSelector.windowName, actualWindowName,
windowSelector.matchType); windowSelector.matchType);
} }
@@ -221,6 +223,13 @@ std::string AttachedWindow::stringify() const {
return os.str(); return os.str();
} }
AttachedWindow::~AttachedWindow()
{
if (xcbConnectionShared && xcbXorg.fns.dereferenceConnection) {
(*xcbXorg.fns.dereferenceConnection)(xcbConnectionShared);
}
}
} // namespace xcb_window } // namespace xcb_window
// SenseApi functions // SenseApi functions
@@ -254,9 +263,13 @@ static int xcbWindow_initializeInd(void)
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_id")); dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_id"));
xcbXorg.fns.findWindowByName = reinterpret_cast<find_window_by_name_fn*>( xcbXorg.fns.findWindowByName = reinterpret_cast<find_window_by_name_fn*>(
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_name")); dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_name"));
xcbXorg.fns.dereferenceConnection =
reinterpret_cast<dereference_connection_fn*>(
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_dereference_connection"));
if (!xcbXorg.fns.getOrCreateConnection || !xcbXorg.fns.cleanupConnections if (!xcbXorg.fns.getOrCreateConnection || !xcbXorg.fns.cleanupConnections
|| !xcbXorg.fns.findWindowById || !xcbXorg.fns.findWindowByName) || !xcbXorg.fns.findWindowById || !xcbXorg.fns.findWindowByName
|| !xcbXorg.fns.dereferenceConnection)
{ {
throw std::runtime_error( throw std::runtime_error(
std::string("xcbWindow:") + __func__ + std::string("xcbWindow:") + __func__ +
@@ -274,7 +287,7 @@ static int xcbWindow_finalizeInd(void)
{ {
dlclose(xcbXorg.dlopenHandle); dlclose(xcbXorg.dlopenHandle);
xcbXorg.dlopenHandle = nullptr; xcbXorg.dlopenHandle = nullptr;
xcbXorg.fns = { nullptr, nullptr, nullptr, nullptr }; xcbXorg.fns = { nullptr, nullptr, nullptr, nullptr, nullptr };
} }
return 0; return 0;
+3 -3
View File
@@ -31,12 +31,12 @@ class AttachedWindow
{ {
public: public:
AttachedWindow(const smo::device::SenseDeviceSpec& spec); AttachedWindow(const smo::device::SenseDeviceSpec& spec);
~AttachedWindow() = default; ~AttachedWindow();
const smo::device::SenseDeviceSpec& getDeviceSpec() const { return deviceSpec; } const smo::device::SenseDeviceSpec& getDeviceSpec() const { return deviceSpec; }
const WindowSelector& getWindowSelector() const { return windowSelector; } const WindowSelector& getWindowSelector() const { return windowSelector; }
const std::string& getActualWindowName() const { return actualWindowName; } const std::string& getActualWindowName() const { return actualWindowName; }
void* getXcbConnection() const { return xcbConnection; } void* getXcbConnection() const { return xcbConnectionShared.get(); }
std::string stringify() const; std::string stringify() const;
private: private:
@@ -47,7 +47,7 @@ private:
smo::device::SenseDeviceSpec deviceSpec; smo::device::SenseDeviceSpec deviceSpec;
WindowSelector windowSelector; WindowSelector windowSelector;
std::string actualWindowName; std::string actualWindowName;
void* xcbConnection; // Raw pointer to XCB connection from libxcbXorg std::shared_ptr<xcb_xorg::XcbConnection> xcbConnectionShared;
}; };
} // namespace xcb_window } // namespace xcb_window