mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-10 02:26:02 -05:00
Refactor window platform helper functions
This commit is contained in:
@@ -178,47 +178,19 @@ void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||
}
|
||||
}
|
||||
|
||||
void checkWindowTitleSwitchDirect(WindowSwitch &s,
|
||||
std::string ¤tWindowTitle, bool &match,
|
||||
OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
static bool windowInfoMatchesSwitch(const WindowInfo &info,
|
||||
const WindowSwitch &s)
|
||||
{
|
||||
bool focus = (!s.focus || s.window == currentWindowTitle);
|
||||
bool fullscreen = (!s.fullscreen || IsFullscreen(s.window));
|
||||
bool max = (!s.maximized || IsMaximized(s.window));
|
||||
|
||||
if (focus && fullscreen && max) {
|
||||
match = true;
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
if (s.focus && !info.focused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void checkWindowTitleSwitchRegex(WindowSwitch &s,
|
||||
std::string ¤tWindowTitle,
|
||||
std::vector<std::string> windowList,
|
||||
bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
for (auto &window : windowList) {
|
||||
try {
|
||||
std::regex expr(s.window);
|
||||
if (!std::regex_match(window, expr)) {
|
||||
continue;
|
||||
}
|
||||
} catch (const std::regex_error &) {
|
||||
}
|
||||
|
||||
bool focus = (!s.focus || window == currentWindowTitle);
|
||||
bool fullscreen = (!s.fullscreen || IsFullscreen(window));
|
||||
bool max = (!s.maximized || IsMaximized(window));
|
||||
|
||||
if (focus && fullscreen && max) {
|
||||
match = true;
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
}
|
||||
if (s.fullscreen && !info.fullscreen) {
|
||||
return false;
|
||||
}
|
||||
if (s.maximized && !info.maximized) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
|
||||
@@ -228,23 +200,37 @@ bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string currentWindowTitle = switcher->currentTitle;
|
||||
bool match = false;
|
||||
const auto windowList = GetWindowList();
|
||||
|
||||
WindowQueryOptions options;
|
||||
options.focus = true;
|
||||
options.fullscreen = true;
|
||||
options.maximized = true;
|
||||
const auto windows = GetWindows(options);
|
||||
|
||||
for (WindowSwitch &s : windowSwitches) {
|
||||
if (!s.initialized()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::find(windowList.begin(), windowList.end(), s.window) !=
|
||||
windowList.end()) {
|
||||
checkWindowTitleSwitchDirect(s, currentWindowTitle,
|
||||
match, scene, transition);
|
||||
} else {
|
||||
checkWindowTitleSwitchRegex(s, currentWindowTitle,
|
||||
windowList, match, scene,
|
||||
transition);
|
||||
for (const auto &info : windows) {
|
||||
bool titleMatch = false;
|
||||
try {
|
||||
std::regex expr(s.window);
|
||||
titleMatch = info.title == s.window ||
|
||||
std::regex_match(info.title, expr);
|
||||
} catch (const std::regex_error &) {
|
||||
titleMatch = info.title == s.window;
|
||||
}
|
||||
|
||||
if (!titleMatch || !windowInfoMatchesSwitch(info, s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match = true;
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
break;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
|
||||
@@ -236,17 +236,65 @@ std::string getWindowName(Window window)
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetWindowList()
|
||||
std::vector<WindowInfo> GetWindows(const WindowQueryOptions &options)
|
||||
{
|
||||
std::vector<std::string> windows;
|
||||
for (auto window : getTopLevelWindows()) {
|
||||
const std::string foregroundTitle = GetCurrentWindowTitle();
|
||||
const auto topLevel = getTopLevelWindows();
|
||||
auto display = disp();
|
||||
|
||||
std::vector<WindowInfo> result;
|
||||
result.reserve(topLevel.size());
|
||||
|
||||
for (auto window : topLevel) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
windows.emplace_back(name);
|
||||
|
||||
WindowInfo info;
|
||||
info.title = name;
|
||||
|
||||
if (options.focus) {
|
||||
info.focused = (name == foregroundTitle);
|
||||
}
|
||||
|
||||
if (options.fullscreen || options.maximized) {
|
||||
QStringList states = getStates(window);
|
||||
if (options.fullscreen) {
|
||||
info.fullscreen = states.contains(
|
||||
"_NET_WM_STATE_FULLSCREEN");
|
||||
}
|
||||
if (options.maximized) {
|
||||
info.maximized =
|
||||
states.contains(
|
||||
"_NET_WM_STATE_MAXIMIZED_VERT") &&
|
||||
states.contains(
|
||||
"_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.geometry && display) {
|
||||
XWindowAttributes attrs;
|
||||
if (XGetWindowAttributes(display, window, &attrs)) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
Window child;
|
||||
XTranslateCoordinates(
|
||||
display, window,
|
||||
DefaultRootWindow(display), 0, 0, &x,
|
||||
&y, &child);
|
||||
info.x = x;
|
||||
info.y = y;
|
||||
info.width = attrs.width;
|
||||
info.height = attrs.height;
|
||||
}
|
||||
}
|
||||
|
||||
// windowClass and text not implemented on Linux
|
||||
result.emplace_back(std::move(info));
|
||||
}
|
||||
return windows;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getActiveWindow(Window *&window)
|
||||
@@ -290,103 +338,6 @@ std::string GetCurrentWindowTitle()
|
||||
return name;
|
||||
}
|
||||
|
||||
bool windowStatesAreSet(const std::string &windowTitle,
|
||||
std::vector<QString> &expectedStates)
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Window> windows = getTopLevelWindows();
|
||||
for (auto &window : windows) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool equals = windowTitle == name;
|
||||
bool matches = QString::fromStdString(name).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(windowTitle)));
|
||||
|
||||
if (!(equals || matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList states = getStates(window);
|
||||
if (states.isEmpty()) {
|
||||
if (expectedStates.empty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &state : expectedStates) {
|
||||
if (!states.contains(state)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMaximized(const std::string &title)
|
||||
{
|
||||
std::vector<QString> states;
|
||||
states.emplace_back("_NET_WM_STATE_MAXIMIZED_VERT");
|
||||
states.emplace_back("_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
bool IsFullscreen(const std::string &title)
|
||||
{
|
||||
std::vector<QString> states;
|
||||
states.emplace_back("_NET_WM_STATE_FULLSCREEN");
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
{
|
||||
// Not implemented
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<WindowGeometry> GetWindowGeometry(const std::string &title)
|
||||
{
|
||||
auto display = disp();
|
||||
if (!display) {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (auto window : getTopLevelWindows()) {
|
||||
if (getWindowName(window) != title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XWindowAttributes attrs;
|
||||
if (!XGetWindowAttributes(display, window, &attrs)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
Window child;
|
||||
XTranslateCoordinates(display, window,
|
||||
DefaultRootWindow(display), 0, 0, &x, &y,
|
||||
&child);
|
||||
|
||||
WindowGeometry geo;
|
||||
geo.x = x;
|
||||
geo.y = y;
|
||||
geo.width = attrs.width;
|
||||
geo.height = attrs.height;
|
||||
return geo;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static void getProcessListProcps(QStringList &processes)
|
||||
{
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
|
||||
@@ -14,41 +14,13 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::vector<std::string> GetWindowList()
|
||||
static std::string nsStringToStdString(NSString *str)
|
||||
{
|
||||
std::vector<std::string> windows;
|
||||
@autoreleasepool {
|
||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
NSMutableArray *apps = (__bridge NSMutableArray *)cfApps;
|
||||
for (NSDictionary *app in apps) {
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner(
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
if (!name.empty() &&
|
||||
find(windows.begin(), windows.end(), name) ==
|
||||
windows.end()) {
|
||||
windows.emplace_back(name);
|
||||
}
|
||||
if (!owner.empty() &&
|
||||
find(windows.begin(), windows.end(), owner) ==
|
||||
windows.end()) {
|
||||
windows.emplace_back(owner);
|
||||
}
|
||||
}
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
return windows;
|
||||
const char *utf8 = [str UTF8String];
|
||||
return utf8 ? utf8 : "";
|
||||
}
|
||||
|
||||
std::string GetCurrentWindowTitle()
|
||||
@@ -148,54 +120,6 @@ bool isWindowMaximizedOnScreen(NSDictionary *app, NSScreen *screen)
|
||||
maximizedTolerance;
|
||||
}
|
||||
|
||||
bool nameMachesPattern(std::string windowName, std::string pattern)
|
||||
{
|
||||
return QString::fromStdString(windowName)
|
||||
.contains(QRegularExpression(QString::fromStdString(pattern)));
|
||||
}
|
||||
|
||||
bool IsMaximized(const std::string &title)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
NSMutableArray *apps = (__bridge NSMutableArray *)cfApps;
|
||||
for (NSDictionary *app in apps) {
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner(
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
bool equals = (title == name || title == owner);
|
||||
bool matches = nameMachesPattern(name, title) ||
|
||||
nameMachesPattern(owner, title);
|
||||
if (equals || matches) {
|
||||
for (NSScreen *screen in screens) {
|
||||
if (isWindowOriginOnScreen(app,
|
||||
screen) &&
|
||||
isWindowMaximizedOnScreen(app,
|
||||
screen)) {
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isWindowFullscreenOnScreen(NSDictionary *app, NSScreen *screen)
|
||||
{
|
||||
NSRect screenFrame = [screen frame];
|
||||
@@ -207,52 +131,100 @@ bool isWindowFullscreenOnScreen(NSDictionary *app, NSScreen *screen)
|
||||
return NSEqualSizes(windowBounds.size, screenFrame.size);
|
||||
}
|
||||
|
||||
bool IsFullscreen(const std::string &title)
|
||||
std::vector<WindowInfo> GetWindows(const WindowQueryOptions &options)
|
||||
{
|
||||
std::vector<WindowInfo> result;
|
||||
const std::string foregroundTitle = GetCurrentWindowTitle();
|
||||
|
||||
@autoreleasepool {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
|
||||
CFArrayRef cfApps = CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
NSMutableArray *apps = (__bridge NSMutableArray *)cfApps;
|
||||
for (NSDictionary *app in apps) {
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
std::string owner(
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
bool equals = (title == name || title == owner);
|
||||
bool matches = nameMachesPattern(name, title) ||
|
||||
nameMachesPattern(owner, title);
|
||||
if (equals || matches) {
|
||||
for (NSScreen *screen in screens) {
|
||||
if (isWindowOriginOnScreen(app, screen,
|
||||
true) &&
|
||||
isWindowFullscreenOnScreen(
|
||||
app, screen)) {
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
return true;
|
||||
// Track titles already added to avoid duplicates (name + owner)
|
||||
std::vector<std::string> seen;
|
||||
|
||||
for (NSDictionary *app in apps) {
|
||||
std::string name = nsStringToStdString(
|
||||
[app objectForKey:@"kCGWindowName"]);
|
||||
std::string owner = nsStringToStdString(
|
||||
[app objectForKey:@"kCGWindowOwnerName"]);
|
||||
|
||||
// Collect geometry once (used for multiple fields)
|
||||
NSRect bounds = NSZeroRect;
|
||||
if (options.geometry || options.fullscreen ||
|
||||
options.maximized) {
|
||||
CGRectMakeWithDictionaryRepresentation(
|
||||
(CFDictionaryRef)[app
|
||||
objectForKey:@"kCGWindowBounds"],
|
||||
&bounds);
|
||||
}
|
||||
|
||||
// Process both the window name and the owner name as
|
||||
// separate entries, matching the old GetWindowList() behaviour
|
||||
for (int pass = 0; pass < 2; ++pass) {
|
||||
const std::string &title = (pass == 0) ? name
|
||||
: owner;
|
||||
if (title.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (std::find(seen.begin(), seen.end(),
|
||||
title) != seen.end()) {
|
||||
continue;
|
||||
}
|
||||
seen.emplace_back(title);
|
||||
|
||||
WindowInfo info;
|
||||
info.title = title;
|
||||
|
||||
if (options.focus) {
|
||||
info.focused =
|
||||
(title == foregroundTitle);
|
||||
}
|
||||
|
||||
if (options.geometry || options.fullscreen ||
|
||||
options.maximized) {
|
||||
info.x = (int)bounds.origin.x;
|
||||
info.y = (int)bounds.origin.y;
|
||||
info.width = (int)bounds.size.width;
|
||||
info.height = (int)bounds.size.height;
|
||||
}
|
||||
|
||||
if (options.fullscreen) {
|
||||
for (NSScreen *screen in screens) {
|
||||
if (isWindowOriginOnScreen(
|
||||
app, screen,
|
||||
true) &&
|
||||
isWindowFullscreenOnScreen(
|
||||
app, screen)) {
|
||||
info.fullscreen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.maximized) {
|
||||
for (NSScreen *screen in screens) {
|
||||
if (isWindowOriginOnScreen(
|
||||
app, screen) &&
|
||||
isWindowMaximizedOnScreen(
|
||||
app, screen)) {
|
||||
info.maximized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// windowClass and text not implemented on macOS
|
||||
result.emplace_back(std::move(info));
|
||||
}
|
||||
}
|
||||
apps = nil;
|
||||
CFRelease(cfApps);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
{
|
||||
// Not implemented
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
|
||||
int SecondsSinceLastInput()
|
||||
@@ -341,8 +313,7 @@ QStringList GetProcessPathsFromName(const QString &name)
|
||||
continue;
|
||||
}
|
||||
const char *nameStr = appName.UTF8String;
|
||||
if (!nameStr ||
|
||||
name != QString::fromUtf8(nameStr)) {
|
||||
if (!nameStr || name != QString::fromUtf8(nameStr)) {
|
||||
continue;
|
||||
}
|
||||
NSURL *url = app.executableURL;
|
||||
|
||||
@@ -11,20 +11,31 @@ namespace advss {
|
||||
|
||||
enum class HotkeyType;
|
||||
|
||||
struct WindowGeometry {
|
||||
struct WindowQueryOptions {
|
||||
bool geometry = false;
|
||||
bool focus = false;
|
||||
bool fullscreen = false;
|
||||
bool maximized = false;
|
||||
bool windowClass = false; // Windows only, no-op on other platforms
|
||||
bool text = false; // Windows only, expensive, no-op on other platforms
|
||||
};
|
||||
|
||||
struct WindowInfo {
|
||||
std::string title;
|
||||
bool focused = false;
|
||||
bool fullscreen = false;
|
||||
bool maximized = false;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
std::string windowClass;
|
||||
std::optional<std::string> text;
|
||||
};
|
||||
|
||||
EXPORT std::vector<std::string> GetWindowList();
|
||||
EXPORT std::vector<WindowInfo>
|
||||
GetWindows(const WindowQueryOptions &options = {});
|
||||
EXPORT std::string GetCurrentWindowTitle();
|
||||
EXPORT bool IsFullscreen(const std::string &title);
|
||||
EXPORT bool IsMaximized(const std::string &title);
|
||||
EXPORT std::optional<std::string> GetTextInWindow(const std::string &window);
|
||||
EXPORT std::optional<WindowGeometry>
|
||||
GetWindowGeometry(const std::string &title);
|
||||
EXPORT int SecondsSinceLastInput();
|
||||
EXPORT QStringList GetProcessList();
|
||||
EXPORT std::string GetForegroundProcessName();
|
||||
|
||||
@@ -173,10 +173,10 @@ void PopulateTransitionSelection(QComboBox *sel, bool addCurrent, bool addAny,
|
||||
void PopulateWindowSelection(QComboBox *sel, bool addSelect)
|
||||
{
|
||||
|
||||
const auto windows = GetWindowList();
|
||||
const auto windows = GetWindows();
|
||||
|
||||
for (const std::string &window : windows) {
|
||||
sel->addItem(window.c_str());
|
||||
for (const auto &info : windows) {
|
||||
sel->addItem(info.title.c_str());
|
||||
}
|
||||
|
||||
sel->model()->sort(0);
|
||||
|
||||
@@ -138,7 +138,7 @@ const std::vector<std::string> getOBSWindows()
|
||||
return lastDoneHelper->windows;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetWindowList()
|
||||
static std::vector<std::string> getAllWindowTitles()
|
||||
{
|
||||
std::vector<std::string> windows;
|
||||
EnumWindowsWithMetro(GetTitleCB, reinterpret_cast<LPARAM>(&windows));
|
||||
@@ -155,6 +155,129 @@ std::vector<std::string> GetWindowList()
|
||||
return windows;
|
||||
}
|
||||
|
||||
static bool isWindowMaximized(HWND hwnd)
|
||||
{
|
||||
if (!hwnd || hwnd == GetDesktopWindow() || hwnd == GetShellWindow()) {
|
||||
return false;
|
||||
}
|
||||
if (IsZoomed(hwnd)) {
|
||||
return true;
|
||||
}
|
||||
RECT appBounds;
|
||||
MONITORINFO monitorInfo = {0};
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||
&monitorInfo);
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
return monitorInfo.rcMonitor.bottom == appBounds.bottom &&
|
||||
monitorInfo.rcMonitor.top == appBounds.top &&
|
||||
monitorInfo.rcMonitor.left == appBounds.left &&
|
||||
monitorInfo.rcMonitor.right == appBounds.right;
|
||||
}
|
||||
|
||||
static bool isWindowFullscreen(HWND hwnd)
|
||||
{
|
||||
if (!hwnd || hwnd == GetDesktopWindow() || hwnd == GetShellWindow()) {
|
||||
return false;
|
||||
}
|
||||
RECT appBounds;
|
||||
MONITORINFO monitorInfo = {0};
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||
&monitorInfo);
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
return monitorInfo.rcMonitor.bottom == appBounds.bottom &&
|
||||
monitorInfo.rcMonitor.top == appBounds.top &&
|
||||
monitorInfo.rcMonitor.left == appBounds.left &&
|
||||
monitorInfo.rcMonitor.right == appBounds.right;
|
||||
}
|
||||
|
||||
static std::string getWindowClass(HWND hwnd)
|
||||
{
|
||||
std::wstring wClass;
|
||||
wClass.resize(256);
|
||||
int len = GetClassNameW(hwnd, &wClass[0], (int)wClass.size());
|
||||
if (len <= 0) {
|
||||
return "";
|
||||
}
|
||||
wClass.resize(len);
|
||||
size_t utf8len = os_wcs_to_utf8(wClass.c_str(), 0, nullptr, 0);
|
||||
std::string result;
|
||||
result.resize(utf8len);
|
||||
os_wcs_to_utf8(wClass.c_str(), 0, &result[0], utf8len + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static HWND getHWNDfromTitle(const std::string &title);
|
||||
static std::optional<std::string> GetTextInWindow(const std::string &window);
|
||||
|
||||
std::vector<WindowInfo> GetWindows(const WindowQueryOptions &options)
|
||||
{
|
||||
const std::string foregroundTitle = GetCurrentWindowTitle();
|
||||
const auto titles = getAllWindowTitles();
|
||||
|
||||
std::vector<WindowInfo> result;
|
||||
result.reserve(titles.size());
|
||||
|
||||
for (const auto &title : titles) {
|
||||
WindowInfo info;
|
||||
info.title = title;
|
||||
|
||||
const bool needHwnd = options.geometry || options.fullscreen ||
|
||||
options.maximized ||
|
||||
options.windowClass || options.text ||
|
||||
options.focus;
|
||||
|
||||
if (options.focus) {
|
||||
info.focused = (title == foregroundTitle);
|
||||
}
|
||||
|
||||
if (!needHwnd || (!options.geometry && !options.fullscreen &&
|
||||
!options.maximized && !options.windowClass &&
|
||||
!options.text)) {
|
||||
result.emplace_back(std::move(info));
|
||||
continue;
|
||||
}
|
||||
|
||||
HWND hwnd = getHWNDfromTitle(title);
|
||||
if (!hwnd) {
|
||||
result.emplace_back(std::move(info));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.geometry || options.fullscreen ||
|
||||
options.maximized) {
|
||||
RECT rect;
|
||||
if (GetWindowRect(hwnd, &rect)) {
|
||||
info.x = rect.left;
|
||||
info.y = rect.top;
|
||||
info.width = rect.right - rect.left;
|
||||
info.height = rect.bottom - rect.top;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.maximized) {
|
||||
info.maximized = isWindowMaximized(hwnd);
|
||||
}
|
||||
|
||||
if (options.fullscreen) {
|
||||
info.fullscreen = isWindowFullscreen(hwnd);
|
||||
}
|
||||
|
||||
if (options.windowClass) {
|
||||
info.windowClass = getWindowClass(hwnd);
|
||||
}
|
||||
|
||||
if (options.text) {
|
||||
info.text = GetTextInWindow(title);
|
||||
}
|
||||
|
||||
result.emplace_back(std::move(info));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetCurrentWindowTitle()
|
||||
{
|
||||
HWND window = GetForegroundWindow();
|
||||
@@ -193,36 +316,6 @@ static HWND getHWNDfromTitle(const std::string &title)
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
bool IsMaximized(const std::string &title)
|
||||
{
|
||||
RECT appBounds;
|
||||
MONITORINFO monitorInfo = {0};
|
||||
HWND hwnd = NULL;
|
||||
|
||||
hwnd = getHWNDfromTitle(title);
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||
&monitorInfo);
|
||||
|
||||
if (hwnd && hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) {
|
||||
if (IsZoomed(hwnd)) {
|
||||
return true;
|
||||
}
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
if (monitorInfo.rcMonitor.bottom == appBounds.bottom &&
|
||||
monitorInfo.rcMonitor.top == appBounds.top &&
|
||||
monitorInfo.rcMonitor.left == appBounds.left &&
|
||||
monitorInfo.rcMonitor.right == appBounds.right) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::wstring GetControlText(HWND hwnd, IUIAutomationElement *element)
|
||||
{
|
||||
VARIANT var;
|
||||
@@ -249,7 +342,7 @@ static std::wstring GetControlText(HWND hwnd, IUIAutomationElement *element)
|
||||
return text;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetTextInWindow(const std::string &window)
|
||||
static std::optional<std::string> GetTextInWindow(const std::string &window)
|
||||
{
|
||||
HWND hwnd = getHWNDfromTitle(window);
|
||||
if (!hwnd) {
|
||||
@@ -316,55 +409,6 @@ std::optional<std::string> GetTextInWindow(const std::string &window)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool IsFullscreen(const std::string &title)
|
||||
{
|
||||
RECT appBounds;
|
||||
MONITORINFO monitorInfo = {0};
|
||||
|
||||
HWND hwnd = NULL;
|
||||
hwnd = getHWNDfromTitle(title);
|
||||
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST),
|
||||
&monitorInfo);
|
||||
|
||||
if (hwnd && hwnd != GetDesktopWindow() && hwnd != GetShellWindow()) {
|
||||
GetWindowRect(hwnd, &appBounds);
|
||||
if (monitorInfo.rcMonitor.bottom == appBounds.bottom &&
|
||||
monitorInfo.rcMonitor.top == appBounds.top &&
|
||||
monitorInfo.rcMonitor.left == appBounds.left &&
|
||||
monitorInfo.rcMonitor.right == appBounds.right) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<WindowGeometry> GetWindowGeometry(const std::string &title)
|
||||
{
|
||||
HWND hwnd = getHWNDfromTitle(title);
|
||||
if (!hwnd) {
|
||||
return {};
|
||||
}
|
||||
|
||||
RECT rect;
|
||||
if (!GetWindowRect(hwnd, &rect)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
WindowGeometry geo;
|
||||
geo.x = rect.left;
|
||||
geo.y = rect.top;
|
||||
geo.width = rect.right - rect.left;
|
||||
geo.height = rect.bottom - rect.top;
|
||||
return geo;
|
||||
}
|
||||
|
||||
QStringList GetProcessList()
|
||||
{
|
||||
QStringList processes;
|
||||
|
||||
Reference in New Issue
Block a user