Compare commits

...

11 Commits

Author SHA1 Message Date
WarmUpTill
7d381b9ba1 Adjust to merge 2021-06-06 19:24:10 +02:00
WarmUpTill
d66a2dc408 Merge branch 'master' into virtual-desktop 2021-06-06 19:14:14 +02:00
WarmUpTill
2ac1a226e2 Implement virtual desktop funcs for windows 2021-05-16 14:58:43 +02:00
WarmUpTill
f56b0b56a7 Merge branch 'master' into virtual-desktop 2021-05-16 13:42:13 +02:00
WarmUpTill
6c1eb3ffab Fix random order of various macro entries 2021-05-15 00:40:43 +02:00
WarmUpTill
e9d6067db2 Show currently active virtual desktop 2021-05-15 00:19:00 +02:00
WarmUpTill
d691492a31 Populate virt desktop selection 2021-05-15 00:04:49 +02:00
WarmUpTill
950dfe8688 Request correct information to get virt desktop count 2021-05-15 00:04:35 +02:00
WarmUpTill
fb38f60609 Drop static used for testing ... 2021-05-14 23:55:23 +02:00
WarmUpTill
3c283a0818 Format 2021-05-14 23:35:57 +02:00
WarmUpTill
271bbcbe95 Add macro condition "virtual desktop" (draft) 2021-05-14 23:34:39 +02:00
8 changed files with 511 additions and 0 deletions

View File

@@ -108,6 +108,7 @@ set(advanced-scene-switcher_HEADERS
src/headers/macro-condition-source.hpp src/headers/macro-condition-source.hpp
src/headers/macro-condition-streaming.hpp src/headers/macro-condition-streaming.hpp
src/headers/macro-condition-video.hpp src/headers/macro-condition-video.hpp
src/headers/macro-condition-virt-desktop.hpp
src/headers/macro-condition-window.hpp src/headers/macro-condition-window.hpp
src/headers/macro.hpp src/headers/macro.hpp
src/headers/macro-selection.hpp src/headers/macro-selection.hpp
@@ -176,6 +177,7 @@ set(advanced-scene-switcher_SOURCES
src/macro-condition-source.cpp src/macro-condition-source.cpp
src/macro-condition-streaming.cpp src/macro-condition-streaming.cpp
src/macro-condition-video.cpp src/macro-condition-video.cpp
src/macro-condition-virt-desktop.cpp
src/macro-condition-window.cpp src/macro-condition-window.cpp
src/macro.cpp src/macro.cpp
src/macro-selection.cpp src/macro-selection.cpp

View File

@@ -124,6 +124,10 @@ AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for {{duratio
AdvSceneSwitcher.condition.pluginState="Plugin state" AdvSceneSwitcher.condition.pluginState="Plugin state"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Automated scene change was triggered in this interval" AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Automated scene change was triggered in this interval"
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}" AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
AdvSceneSwitcher.condition.virtDesktop="Virtual desktop"
AdvSceneSwitcher.condition.virtDesktop.notAvailable="Not availbale"
AdvSceneSwitcher.condition.virtDesktop.entry.line1="Active virtual desktop is {{virtDesktops}}"
AdvSceneSwitcher.condition.virtDesktop.entry.line2="Current: {{currentDesktop}}"
AdvSceneSwitcher.condition.interval="Interval" AdvSceneSwitcher.condition.interval="Interval"
AdvSceneSwitcher.condition.interval.entry="{{duration}} have passed" AdvSceneSwitcher.condition.interval.entry="{{duration}} have passed"
AdvSceneSwitcher.condition.counter="Count" AdvSceneSwitcher.condition.counter="Count"

View File

@@ -0,0 +1,51 @@
#pragma once
#include "macro.hpp"
#include <QWidget>
#include <QComboBox>
class MacroConditionVirtDesktop : public MacroCondition {
public:
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
{
return std::make_shared<MacroConditionVirtDesktop>();
}
long _desktop = 0;
private:
static bool _registered;
static const std::string id;
};
class MacroConditionVirtDesktopEdit : public QWidget {
Q_OBJECT
public:
MacroConditionVirtDesktopEdit(
QWidget *parent,
std::shared_ptr<MacroConditionVirtDesktop> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionVirtDesktopEdit(
parent,
std::dynamic_pointer_cast<MacroConditionVirtDesktop>(
cond));
}
private slots:
void DesktopChanged(int value);
void UpdateCurrentDesktop();
protected:
QComboBox *_virtDesktops;
QLabel *_currentDesktop;
std::shared_ptr<MacroConditionVirtDesktop> _entryData;
private:
bool _loading = true;
};

View File

@@ -9,3 +9,5 @@ std::pair<int, int> getCursorPos();
int secondsSinceLastInput(); int secondsSinceLastInput();
void GetProcessList(QStringList &processes); void GetProcessList(QStringList &processes);
bool isInFocus(const QString &executable); bool isInFocus(const QString &executable);
bool GetCurrentVirtualDesktop(long &desktop);
bool GetVirtualDesktopCount(long &ndesktops);

View File

@@ -393,3 +393,67 @@ int secondsSinceLastInput()
return idle_time; return idle_time;
} }
bool GetCurrentVirtualDesktop(long &desktop)
{
Atom type;
long unsigned nitems;
long unsigned int bytes = 0;
int format = 0;
unsigned char *data;
Window root;
Atom request;
Display *display = disp();
//TODO check for _NET_CURRENT_DESKTOP
if (!ewmhIsSupported()) {
return false;
}
request = XInternAtom(display, "_NET_CURRENT_DESKTOP", False);
root = XDefaultRootWindow(display);
int status = XGetWindowProperty(display, root, request, 0L, 1L, false,
XA_CARDINAL, &type, &format, &nitems,
&bytes, &data);
if (status == Success && nitems > 0) {
desktop = *((long *)data);
} else {
desktop = -1;
}
free(data);
return desktop != -1;
}
bool GetVirtualDesktopCount(long &ndesktops)
{
Atom type;
long unsigned nitems;
long unsigned int bytes = 0;
int format = 0;
unsigned char *data;
Window root;
Atom request;
Display *display = disp();
//TODO check for _NET_NUMBER_OF_DESKTOPS
if (!ewmhIsSupported()) {
return false;
}
request = XInternAtom(display, "_NET_NUMBER_OF_DESKTOPS", False);
root = XDefaultRootWindow(display);
int status = XGetWindowProperty(display, root, request, 0L, 1L, false,
XA_CARDINAL, &type, &format, &nitems,
&bytes, &data);
if (status == Success && nitems > 0) {
ndesktops = *((long *)data);
} else {
ndesktops = 0;
}
free(data);
return ndesktops != 0;
}

View File

@@ -0,0 +1,113 @@
#include "headers/macro-condition-edit.hpp"
#include "headers/macro-condition-virt-desktop.hpp"
#include "headers/utility.hpp"
#include "headers/advanced-scene-switcher.hpp"
const std::string MacroConditionVirtDesktop::id = "virtual_desktop";
bool MacroConditionVirtDesktop::_registered = MacroConditionFactory::Register(
MacroConditionVirtDesktop::id,
{MacroConditionVirtDesktop::Create,
MacroConditionVirtDesktopEdit::Create,
"AdvSceneSwitcher.condition.virtDesktop"});
bool MacroConditionVirtDesktop::CheckCondition()
{
long curDesktop;
GetCurrentVirtualDesktop(curDesktop);
return _desktop == curDesktop;
}
bool MacroConditionVirtDesktop::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
obs_data_set_int(obj, "desktop", static_cast<int>(_desktop));
return true;
}
bool MacroConditionVirtDesktop::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_desktop = obs_data_get_int(obj, "desktop");
return true;
}
static void populateVirtualDesktopSelection(QComboBox *list)
{
long count;
GetVirtualDesktopCount(count);
for (long i = 0; i < count; i++) {
list->addItem(std::to_string(i).c_str());
}
}
MacroConditionVirtDesktopEdit::MacroConditionVirtDesktopEdit(
QWidget *parent, std::shared_ptr<MacroConditionVirtDesktop> entryData)
: QWidget(parent)
{
_currentDesktop = new QLabel();
_currentDesktop->setTextInteractionFlags(Qt::TextSelectableByMouse);
_virtDesktops = new QComboBox();
QWidget::connect(_virtDesktops, SIGNAL(currentIndexChanged(int)), this,
SLOT(DesktopChanged(int)));
populateVirtualDesktopSelection(_virtDesktops);
QVBoxLayout *mainLayout = new QVBoxLayout;
QHBoxLayout *line1Layout = new QHBoxLayout;
QHBoxLayout *line2Layout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{virtDesktops}}", _virtDesktops},
{"{{currentDesktop}}", _currentDesktop},
};
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.virtDesktop.entry.line1"),
line1Layout, widgetPlaceholders);
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.virtDesktop.entry.line2"),
line2Layout, widgetPlaceholders);
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
setLayout(mainLayout);
// Current virtual desktop position
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(UpdateCurrentDesktop()));
timer->start(1000);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroConditionVirtDesktopEdit::DesktopChanged(int value)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_desktop = value;
}
void MacroConditionVirtDesktopEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_virtDesktops->setCurrentIndex(_entryData->_desktop);
}
void MacroConditionVirtDesktopEdit::UpdateCurrentDesktop()
{
long curDesktop;
if (GetCurrentVirtualDesktop(curDesktop)) {
_currentDesktop->setText(QString::number(curDesktop));
} else {
_currentDesktop->setText(obs_module_text(
"AdvSceneSwitcher.condition.virtDesktop.notAvailable"));
}
}

View File

@@ -281,3 +281,13 @@ bool isInFocus(const QString &executable)
return (equals || matches); return (equals || matches);
} }
bool GetCurrentVirtualDesktop(long &desktop)
{
return false;
}
bool GetVirtualDesktopCount(long &ndesktops)
{
return false;
}

View File

@@ -1,5 +1,7 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <objectarray.h>
#include <shobjidl_core.h>
#include <util/platform.h> #include <util/platform.h>
#include <TlHelp32.h> #include <TlHelp32.h>
#include <Psapi.h> #include <Psapi.h>
@@ -11,6 +13,7 @@
#include <QRegularExpression> #include <QRegularExpression>
#define MAX_SEARCH 1000 #define MAX_SEARCH 1000
#define MAXDESKTOPS 255
static bool GetWindowTitle(HWND window, std::string &title) static bool GetWindowTitle(HWND window, std::string &title)
{ {
@@ -285,3 +288,265 @@ int secondsSinceLastInput()
{ {
return (getTime() - getLastInputTime()) / 1000; return (getTime() - getLastInputTime()) / 1000;
} }
// Virtual Desktop code
// based on https://github.com/Eun/MoveToDesktop/
//
// TODO:
// - clean up
// - call FreeCom() on exit
struct IApplicationView : public IUnknown {
public:
};
MIDL_INTERFACE("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")
IVirtualDesktop : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE IsViewVisible(
IApplicationView * pView, int *pfVisible) = 0;
virtual HRESULT STDMETHODCALLTYPE GetID(GUID * pGuid) = 0;
};
class IVirtualDesktopManagerInternal : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE GetCount(UINT *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE MoveViewToDesktop(
IApplicationView *pView, IVirtualDesktop *pDesktop) = 0;
// 10240
virtual HRESULT STDMETHODCALLTYPE CanViewMoveDesktops(
IApplicationView *pView, int *pfCanViewMoveDesktops) = 0;
virtual HRESULT STDMETHODCALLTYPE
GetCurrentDesktop(IVirtualDesktop **desktop) = 0;
virtual HRESULT STDMETHODCALLTYPE
GetDesktops(IObjectArray **ppDesktops) = 0;
virtual HRESULT STDMETHODCALLTYPE
SwitchDesktop(IVirtualDesktop *pDesktop) = 0;
virtual HRESULT STDMETHODCALLTYPE
CreateDesktopW(IVirtualDesktop **ppNewDesktop) = 0;
// pFallbackDesktop - ??????? ???? ?? ??????? ????? ???????? ??????? ????? ???????? ??????????
virtual HRESULT STDMETHODCALLTYPE
RemoveDesktop(IVirtualDesktop *pRemove,
IVirtualDesktop *pFallbackDesktop) = 0;
// 10240
virtual HRESULT STDMETHODCALLTYPE
FindDesktop(GUID *desktopId, IVirtualDesktop **ppDesktop) = 0;
};
IServiceProvider *pServiceProvider = nullptr;
IVirtualDesktopManager *pDesktopManager = nullptr;
IVirtualDesktopManagerInternal *pDesktopManagerInternal = nullptr;
const CLSID CLSID_ImmersiveShell = {0xC2F03A33, 0x21F5, 0x47FA, 0xB4,
0xBB, 0x15, 0x63, 0x62,
0xA2, 0xF2, 0x39};
const CLSID CLSID_VirtualDesktopAPI_Unknown = {0xC5E0CDCA, 0x7B6E, 0x41B2, 0x9F,
0xC4, 0xD9, 0x39, 0x75,
0xCC, 0x46, 0x7B};
const IID IID_IVirtualDesktopManagerInternal = {0xEF9F1A6C, 0xD3CC, 0x4358,
0xB7, 0x12, 0xF8,
0x4B, 0x63, 0x5B,
0xEB, 0xE7};
const IID UUID_IVirtualDesktopManagerInternal_10130{0xEF9F1A6C, 0xD3CC, 0x4358,
0xB7, 0x12, 0xF8,
0x4B, 0x63, 0x5B,
0xEB, 0xE7};
const IID UUID_IVirtualDesktopManagerInternal_10240{0xAF8DA486, 0x95BB, 0x4460,
0xB3, 0xB7, 0x6E,
0x7A, 0x6B, 0x29,
0x62, 0xB5};
const IID UUID_IVirtualDesktopManagerInternal_14393{0xf31574d6, 0xb682, 0x4cdc,
0xbd, 0x56, 0x18,
0x27, 0x86, 0x0a,
0xbe, 0xc6};
enum EComStatus {
COMSTATUS_UNINITIALIZED,
COMSTATUS_INITIALIZED,
COMSTATUS_ERROR,
};
int ComStatus = COMSTATUS_UNINITIALIZED;
#define COMMAND_TIMEOUT 500 // Blocks Command below this timeout
bool bAddedMenu = false;
bool bReadIni = false;
bool bSwitchDesktopAfterMove = false;
bool bCreateNewDesktopOnMove = false;
bool bDeleteEmptyDesktops = true;
ULONGLONG nLastCommand = 0;
UINT16 GetWinBuildNumber()
{
UINT16 buildNumbers[] = {10130, 10240, 14393};
OSVERSIONINFOEXW osvi = {sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0};
ULONGLONG mask = ::VerSetConditionMask(0, VER_BUILDNUMBER, VER_EQUAL);
for (size_t i = 0; i < sizeof(buildNumbers) / sizeof(buildNumbers[0]);
i++) {
osvi.dwBuildNumber = buildNumbers[i];
if (VerifyVersionInfoW(&osvi, VER_BUILDNUMBER, mask) != FALSE) {
return buildNumbers[i];
}
}
return 0;
}
BOOL InitCom()
{
if (ComStatus == COMSTATUS_INITIALIZED) {
return true;
} else if (ComStatus == COMSTATUS_ERROR) {
return false;
}
ComStatus = COMSTATUS_ERROR;
HRESULT hr = ::CoInitialize(NULL);
if (FAILED(hr)) {
return FALSE;
}
hr = ::CoCreateInstance(CLSID_ImmersiveShell, NULL, CLSCTX_LOCAL_SERVER,
__uuidof(IServiceProvider),
(PVOID *)&pServiceProvider);
if (FAILED(hr)) {
return FALSE;
}
hr = pServiceProvider->QueryService(__uuidof(IVirtualDesktopManager),
&pDesktopManager);
if (FAILED(hr)) {
pServiceProvider->Release();
pServiceProvider = nullptr;
return FALSE;
}
UINT16 buildNumber = GetWinBuildNumber();
switch (buildNumber) {
case 10130:
hr = pServiceProvider->QueryService(
CLSID_VirtualDesktopAPI_Unknown,
UUID_IVirtualDesktopManagerInternal_10130,
(void **)&pDesktopManagerInternal);
break;
case 10240:
hr = pServiceProvider->QueryService(
CLSID_VirtualDesktopAPI_Unknown,
UUID_IVirtualDesktopManagerInternal_10240,
(void **)&pDesktopManagerInternal);
break;
case 14393:
default:
hr = pServiceProvider->QueryService(
CLSID_VirtualDesktopAPI_Unknown,
UUID_IVirtualDesktopManagerInternal_14393,
(void **)&pDesktopManagerInternal);
break;
}
if (FAILED(hr)) {
pDesktopManager->Release();
pDesktopManager = nullptr;
pServiceProvider->Release();
pServiceProvider = nullptr;
return FALSE;
}
ComStatus = COMSTATUS_INITIALIZED;
return TRUE;
}
VOID FreeCom()
{
if (ComStatus == COMSTATUS_INITIALIZED) {
pDesktopManager->Release();
pDesktopManagerInternal->Release();
pServiceProvider->Release();
ComStatus = COMSTATUS_UNINITIALIZED;
}
}
bool GetCurrentVirtualDesktop(long &desktop)
{
UINT count = 0;
IObjectArray *pObjectArray = nullptr;
IVirtualDesktop *pCurrentDesktop = nullptr;
if (!InitCom()) {
return false;
}
HRESULT hr = pDesktopManagerInternal->GetDesktops(&pObjectArray);
if (FAILED(hr)) {
return false;
}
hr = pObjectArray->GetCount(&count);
if (FAILED(hr)) {
pObjectArray->Release();
return false;
}
hr = pDesktopManagerInternal->GetCurrentDesktop(&pCurrentDesktop);
if (FAILED(hr)) {
pObjectArray->Release();
return false;
}
int index = -1;
for (UINT i = 0; i < count && i < MAXDESKTOPS && index == -1; ++i) {
IVirtualDesktop *pDesktop = nullptr;
if (FAILED(pObjectArray->GetAt(i, __uuidof(IVirtualDesktop),
(void **)&pDesktop)))
continue;
if (pDesktop == pCurrentDesktop) {
index = i;
}
pDesktop->Release();
}
pObjectArray->Release();
if (pCurrentDesktop != nullptr) {
pCurrentDesktop->Release();
}
desktop = index;
return true;
}
bool GetVirtualDesktopCount(long &ndesktops)
{
if (!InitCom()) {
return false;
}
IObjectArray *pObjectArray = nullptr;
HRESULT hr = pDesktopManagerInternal->GetDesktops(&pObjectArray);
if (FAILED(hr)) {
return false;
}
UINT count;
hr = pObjectArray->GetCount(&count);
if (FAILED(hr)) {
pObjectArray->Release();
return false;
}
pObjectArray->Release();
ndesktops = count;
return true;
}