xcbXorg: Use apiParams to choose match method for window attachment
We now use param keys in the API params to choose what type of ID the deviceSelector holds, and how to match it. * dev-id/devid: matches by ID. * dev-substr/dev-substring/devsubstr: Matches window name by substring. * dev-string/devstr/dev-str: matches window name by exact whole string.
This commit is contained in:
@@ -127,12 +127,15 @@ namespace xcb_window_search {
|
|||||||
void operator()(xcb_get_property_reply_t* p) { free(p); }
|
void operator()(xcb_get_property_reply_t* p) { free(p); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class MatchType { SUBSTRING, EXACT, ID };
|
||||||
|
|
||||||
static xcb_window_t findById(
|
static 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);
|
||||||
|
|
||||||
static xcb_window_t findByName(
|
static xcb_window_t findByName(
|
||||||
xcb_connection_t* conn, xcb_window_t root,
|
xcb_connection_t* conn, xcb_window_t root,
|
||||||
const std::string& targetName, std::string& outWindowName);
|
const std::string& targetName, std::string& outWindowName,
|
||||||
|
MatchType matchType);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AttachedDevice
|
class AttachedDevice
|
||||||
@@ -140,23 +143,31 @@ class AttachedDevice
|
|||||||
public:
|
public:
|
||||||
struct WindowSelector
|
struct WindowSelector
|
||||||
{
|
{
|
||||||
|
xcb_window_search::MatchType matchType;
|
||||||
|
|
||||||
XcbConnection::XConnectionIdentifier xconn;
|
XcbConnection::XConnectionIdentifier xconn;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
std::string name;
|
std::string name;
|
||||||
} window;
|
} window;
|
||||||
bool useWindowId;
|
|
||||||
|
|
||||||
std::string stringify() const
|
std::string stringify() const
|
||||||
{
|
{
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
||||||
os << "Display: " << xconn.display
|
os << "Display: " << xconn.display
|
||||||
<< ", Screen: " << xconn.screen
|
<< ", Screen: " << xconn.screen << ", Window: ";
|
||||||
<< ", Window: " << (useWindowId
|
if (matchType == xcb_window_search::MatchType::ID) {
|
||||||
? std::to_string(window.id)
|
os << window.id;
|
||||||
: "\"" + window.name + "\"");
|
} else {
|
||||||
|
os << "\"" << window.name << "\"";
|
||||||
|
}
|
||||||
|
os << " (matchType="
|
||||||
|
<< (matchType == xcb_window_search::MatchType::EXACT
|
||||||
|
? "exact" :
|
||||||
|
(matchType == xcb_window_search::MatchType::SUBSTRING)
|
||||||
|
? "substring" : "id")
|
||||||
|
<< ")";
|
||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -169,7 +180,7 @@ public:
|
|||||||
{
|
{
|
||||||
windowSelector.xconn.display = getRequiredParamAsInt(spec, "display");
|
windowSelector.xconn.display = getRequiredParamAsInt(spec, "display");
|
||||||
windowSelector.xconn.screen = getRequiredParamAsInt(spec, "screen");
|
windowSelector.xconn.screen = getRequiredParamAsInt(spec, "screen");
|
||||||
parseWindowSelector(spec.deviceSelector, windowSelector);
|
parseWindowSelector(spec, windowSelector);
|
||||||
|
|
||||||
// Get the root window
|
// Get the root window
|
||||||
const xcb_setup_t* setup = xcb_get_setup(connection->connection.get());
|
const xcb_setup_t* setup = xcb_get_setup(connection->connection.get());
|
||||||
@@ -181,7 +192,7 @@ public:
|
|||||||
|
|
||||||
// Search for window
|
// Search for window
|
||||||
xcb_window_t targetWindow = 0;
|
xcb_window_t targetWindow = 0;
|
||||||
if (windowSelector.useWindowId)
|
if (windowSelector.matchType == xcb_window_search::MatchType::ID)
|
||||||
{
|
{
|
||||||
targetWindow = xcb_window_search::findById(
|
targetWindow = xcb_window_search::findById(
|
||||||
connection->connection.get(), root, windowSelector.window.id);
|
connection->connection.get(), root, windowSelector.window.id);
|
||||||
@@ -190,14 +201,15 @@ public:
|
|||||||
{
|
{
|
||||||
targetWindow = xcb_window_search::findByName(
|
targetWindow = xcb_window_search::findByName(
|
||||||
connection->connection.get(), root,
|
connection->connection.get(), root,
|
||||||
windowSelector.window.name, actualWindowName);
|
windowSelector.window.name, actualWindowName,
|
||||||
|
windowSelector.matchType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetWindow)
|
if (!targetWindow)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Failed to find window "
|
"Failed to find window "
|
||||||
+ (windowSelector.useWindowId
|
+ (windowSelector.matchType == xcb_window_search::MatchType::ID
|
||||||
? std::to_string(windowSelector.window.id)
|
? std::to_string(windowSelector.window.id)
|
||||||
: "\"" + windowSelector.window.name + "\"")
|
: "\"" + windowSelector.window.name + "\"")
|
||||||
+ " on display " + std::to_string(windowSelector.xconn.display)
|
+ " on display " + std::to_string(windowSelector.xconn.display)
|
||||||
@@ -239,30 +251,47 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void parseWindowSelector(
|
static void parseWindowSelector(
|
||||||
const std::string& selector,
|
const hk::device::SenseDeviceSpec& spec,
|
||||||
WindowSelector& windowSelector)
|
WindowSelector& windowSelector)
|
||||||
{
|
{
|
||||||
if (selector.length() >= 2 &&
|
// Default match type
|
||||||
((selector[0] == '"' && selector.back() == '"') ||
|
windowSelector.matchType = xcb_window_search::MatchType::SUBSTRING;
|
||||||
(selector[0] == '\'' && selector.back() == '\'') ||
|
|
||||||
(selector[0] == '`' && selector.back() == '`')))
|
// Check if 'dev-id', 'dev-string', or 'dev-substring' is specified
|
||||||
|
for (const auto& param : spec.apiParams)
|
||||||
{
|
{
|
||||||
windowSelector.window.name = selector.substr(
|
if (param.first == "dev-id" || param.first == "devid")
|
||||||
1, selector.length() - 2);
|
{
|
||||||
windowSelector.useWindowId = false;
|
windowSelector.matchType = xcb_window_search::MatchType::ID;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
if (param.first == "dev-string"
|
||||||
|
|| param.first == "dev-str" || param.first == "devstr")
|
||||||
|
{
|
||||||
|
windowSelector.matchType = xcb_window_search::MatchType::EXACT;
|
||||||
|
}
|
||||||
|
if (param.first == "dev-substring"
|
||||||
|
|| param.first == "dev-substr" || param.first == "devsubstr")
|
||||||
|
{
|
||||||
|
windowSelector.matchType = xcb_window_search::
|
||||||
|
MatchType::SUBSTRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowSelector.matchType == xcb_window_search::MatchType::ID)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Allow hex numbers
|
windowSelector.window.id = std::stoul(
|
||||||
windowSelector.window.id = std::stoul(selector, nullptr, 0);
|
spec.deviceSelector, nullptr, 0);
|
||||||
windowSelector.useWindowId = true;
|
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Window selector must be either a quoted string or a "
|
"Window selector: 'dev-id' present, but selector is not "
|
||||||
"numeric ID");
|
"numeric");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
windowSelector.window.name = spec.deviceSelector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -310,7 +339,8 @@ static xcb_window_t findById(
|
|||||||
|
|
||||||
static xcb_window_t findByName(
|
static xcb_window_t findByName(
|
||||||
xcb_connection_t* conn, xcb_window_t root,
|
xcb_connection_t* conn, xcb_window_t root,
|
||||||
const std::string& targetName, std::string& outWindowName)
|
const std::string& targetName, std::string& outWindowName,
|
||||||
|
MatchType matchType)
|
||||||
{
|
{
|
||||||
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(
|
||||||
@@ -332,7 +362,10 @@ static xcb_window_t findByName(
|
|||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
std::string windowName(name, len);
|
std::string windowName(name, len);
|
||||||
if (windowName == targetName)
|
if ((matchType == MatchType::EXACT
|
||||||
|
&& windowName == targetName)
|
||||||
|
|| (matchType == MatchType::SUBSTRING
|
||||||
|
&& windowName.find(targetName) != std::string::npos))
|
||||||
{
|
{
|
||||||
outWindowName = windowName;
|
outWindowName = windowName;
|
||||||
return root;
|
return root;
|
||||||
@@ -359,7 +392,10 @@ static xcb_window_t findByName(
|
|||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
std::string windowName(name, len);
|
std::string windowName(name, len);
|
||||||
if (windowName == targetName)
|
if ((matchType == MatchType::EXACT
|
||||||
|
&& windowName == targetName)
|
||||||
|
|| (matchType == MatchType::SUBSTRING
|
||||||
|
&& windowName.find(targetName) != std::string::npos))
|
||||||
{
|
{
|
||||||
outWindowName = windowName;
|
outWindowName = windowName;
|
||||||
return children[i];
|
return children[i];
|
||||||
@@ -369,7 +405,7 @@ static xcb_window_t findByName(
|
|||||||
|
|
||||||
// Recursively search this child's subtree
|
// Recursively search this child's subtree
|
||||||
if (xcb_window_t result = findByName(
|
if (xcb_window_t result = findByName(
|
||||||
conn, children[i], targetName, outWindowName))
|
conn, children[i], targetName, outWindowName, matchType))
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user