diff --git a/commonLibs/xcbXorg/xcbXorg.cpp b/commonLibs/xcbXorg/xcbXorg.cpp index 6b4f314..8760e41 100644 --- a/commonLibs/xcbXorg/xcbXorg.cpp +++ b/commonLibs/xcbXorg/xcbXorg.cpp @@ -73,6 +73,18 @@ size_t ConnectionManager::getConnectionCount() 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 { struct XcbReplyDeleter { @@ -83,14 +95,14 @@ struct XcbReplyDeleter { xcb_window_t findById( 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); std::unique_ptr reply( xcb_query_tree_reply(conn, cookie, nullptr)); if (!reply) return 0; + if (root == targetId) return root; + xcb_window_t* children = xcb_query_tree_children(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, 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 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()); + } +} diff --git a/commonLibs/xcbXorg/xcbXorg.h b/commonLibs/xcbXorg/xcbXorg.h index faf88e4..4bb83c2 100644 --- a/commonLibs/xcbXorg/xcbXorg.h +++ b/commonLibs/xcbXorg/xcbXorg.h @@ -126,6 +126,12 @@ public: */ 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: static std::map> connections; }; @@ -167,6 +173,8 @@ xcb_window_t findByName(xcb_connection_t* conn, xcb_window_t root, typedef std::shared_ptr get_or_create_connection_fn( int display, int screen); typedef void cleanup_connections_fn(); +typedef void dereference_connection_fn( + std::shared_ptr conn); typedef xcb_window_t find_window_by_id_fn( void* conn, xcb_window_t root, uint32_t targetId); typedef xcb_window_t find_window_by_name_fn(void* conn, xcb_window_t root, diff --git a/senseApis/xcbWindow/xcbWindow.cpp b/senseApis/xcbWindow/xcbWindow.cpp index 6ca2c59..be975e3 100644 --- a/senseApis/xcbWindow/xcbWindow.cpp +++ b/senseApis/xcbWindow/xcbWindow.cpp @@ -18,6 +18,7 @@ struct XcbXorgDllState { get_or_create_connection_fn* getOrCreateConnection = nullptr; cleanup_connections_fn* cleanupConnections = nullptr; + dereference_connection_fn* dereferenceConnection = nullptr; find_window_by_id_fn* findWindowById = nullptr; find_window_by_name_fn* findWindowByName = nullptr; } fns; @@ -54,11 +55,12 @@ std::string WindowSelector::stringify() const } AttachedWindow::AttachedWindow(const smo::device::SenseDeviceSpec& spec) - : deviceSpec(spec), xcbConnection(nullptr) + : deviceSpec(spec) { // Validate required function pointers are available 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__) + ": Required xcbXorg function pointers not available"); @@ -73,7 +75,7 @@ AttachedWindow::AttachedWindow(const smo::device::SenseDeviceSpec& spec) (*xcbXorg.fns.getOrCreateConnection)( windowSelector.display, windowSelector.screen); - xcbConnection = conn.get(); + xcbConnectionShared = conn; // Find the target window 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) { foundWindow = (*xcbXorg.fns.findWindowById)( - xcbConnection, screen->root, + conn.get(), screen->root, windowSelector.windowId); } else { foundWindow = (*xcbXorg.fns.findWindowByName)( - xcbConnection, screen->root, + conn.get(), screen->root, windowSelector.windowName, actualWindowName, windowSelector.matchType); } @@ -221,6 +223,13 @@ std::string AttachedWindow::stringify() const { return os.str(); } +AttachedWindow::~AttachedWindow() +{ + if (xcbConnectionShared && xcbXorg.fns.dereferenceConnection) { + (*xcbXorg.fns.dereferenceConnection)(xcbConnectionShared); + } +} + } // namespace xcb_window // SenseApi functions @@ -254,9 +263,13 @@ static int xcbWindow_initializeInd(void) dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_id")); xcbXorg.fns.findWindowByName = reinterpret_cast( dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_name")); + xcbXorg.fns.dereferenceConnection = + reinterpret_cast( + dlsym(xcbXorg.dlopenHandle, "xcb_xorg_dereference_connection")); 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( std::string("xcbWindow:") + __func__ + @@ -274,7 +287,7 @@ static int xcbWindow_finalizeInd(void) { dlclose(xcbXorg.dlopenHandle); xcbXorg.dlopenHandle = nullptr; - xcbXorg.fns = { nullptr, nullptr, nullptr, nullptr }; + xcbXorg.fns = { nullptr, nullptr, nullptr, nullptr, nullptr }; } return 0; diff --git a/senseApis/xcbWindow/xcbWindow.h b/senseApis/xcbWindow/xcbWindow.h index fd645a7..5aab84a 100644 --- a/senseApis/xcbWindow/xcbWindow.h +++ b/senseApis/xcbWindow/xcbWindow.h @@ -31,12 +31,12 @@ class AttachedWindow { public: AttachedWindow(const smo::device::SenseDeviceSpec& spec); - ~AttachedWindow() = default; + ~AttachedWindow(); const smo::device::SenseDeviceSpec& getDeviceSpec() const { return deviceSpec; } const WindowSelector& getWindowSelector() const { return windowSelector; } const std::string& getActualWindowName() const { return actualWindowName; } - void* getXcbConnection() const { return xcbConnection; } + void* getXcbConnection() const { return xcbConnectionShared.get(); } std::string stringify() const; private: @@ -47,7 +47,7 @@ private: smo::device::SenseDeviceSpec deviceSpec; WindowSelector windowSelector; std::string actualWindowName; - void* xcbConnection; // Raw pointer to XCB connection from libxcbXorg + std::shared_ptr xcbConnectionShared; }; } // namespace xcb_window