Files
SysTray-X/app/SysTray-X/windowctrl-win.cpp
2020-04-30 19:39:12 +02:00

438 lines
7.6 KiB
C++

#include "windowctrl-win.h"
#ifdef Q_OS_WIN
/*
* System includes
*/
#include <TlHelp32.h>
#include <Psapi.h>
#include <CommCtrl.h>
/*
* Standard library includes
*/
#include <array>
/*
* Qt includes
*/
#include <QCoreApplication>
#include <QString>
/*
* Initialize statics
*/
WindowCtrlWin* WindowCtrlWin::m_ctrl_parent = nullptr;
/*
* Constructor
*/
WindowCtrlWin::WindowCtrlWin( QObject *parent) : QObject( parent )
{
/*
* Initialize
*/
m_tb_window = 0;
m_tb_windows = QList< quint64 >();
m_window_state = QString();
/*
* Setup the minimize intercept
*/
m_ctrl_parent = this;
interceptMinimizeWindow();
}
/*
* Destructor
*/
WindowCtrlWin::~WindowCtrlWin()
{
/*
* Remove the intercept hook
*/
stopInterceptMinimizeWindow();
}
/*
* Set the window state.
*/
void WindowCtrlWin::setWindowState( const QString& state )
{
m_window_state = state;
}
/**
* @brief getWindowState. Get the window state.
*
* @return The state.
*/
const QString& WindowCtrlWin::getWindowState() const
{
return m_window_state;
}
/*
* Set the minimize type
*/
void WindowCtrlWin::setMinimizeType( Preferences::MinimizeType type )
{
m_minimize_type = type;
}
/*
* Get the minimize type
*/
Preferences::MinimizeType WindowCtrlWin::getMinimizeType() const
{
return m_minimize_type;
}
/*
* Get the parent pid of SysTray-X, TB hopefully
*/
qint64 WindowCtrlWin::getPpid()
{
HANDLE h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
PROCESSENTRY32 pe;
pe.dwSize = sizeof( PROCESSENTRY32 );
qint64 ppid = -1;
qint64 pid = QCoreApplication::applicationPid();
if( Process32First( h, &pe ) )
{
do
{
if( pe.th32ProcessID == pid )
{
ppid = pe.th32ParentProcessID;
break;
}
}
while( Process32Next( h, &pe ) );
}
CloseHandle( h );
return ppid;
}
/*
* Is the pid from thunderbird
*/
bool WindowCtrlWin::isThunderbird( qint64 pid )
{
return getProcessName( pid ).contains( "thunderbird", Qt::CaseInsensitive );
}
/*
* Get the process name
*/
QString WindowCtrlWin::getProcessName( qint64 pid )
{
HANDLE proc = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid );
char name[ 256 ];
GetModuleBaseNameA( proc, nullptr, name, 256);
return QString( name );
}
/*
* Find the window by title
*/
bool WindowCtrlWin::findWindow( const QString& title )
{
m_tb_windows = QList< quint64 >();
EnumWindowsTitleProcData data{ *this, title.toStdString() };
EnumWindows( &enumWindowsTitleProc, reinterpret_cast<LPARAM>(&data) );
if( m_tb_windows.length() == 0 )
{
return false;
}
return true;
}
/*
* Callback for the window enumaration title find.
*/
BOOL CALLBACK WindowCtrlWin::enumWindowsTitleProc( HWND hwnd, LPARAM lParam )
{
auto& data = *reinterpret_cast<EnumWindowsTitleProcData*>(lParam);
std::array<char, 128> buffer;
int written = GetWindowTextA( hwnd, buffer.data(), int(buffer.size()) );
if( written && strstr( buffer.data(), data.title.c_str() ) != nullptr )
{
data.window_ctrl.m_tb_windows.append( (quint64)hwnd );
}
return TRUE;
}
/*
* Find the window by pid
*/
bool WindowCtrlWin::findWindow( qint64 pid )
{
EnumWindowsPidProcData data;
data.pid = pid;
data.hwnd = nullptr;
EnumWindows( &enumWindowsPidProc, reinterpret_cast<LPARAM>(&data) );
if( data.hwnd == nullptr )
{
return false;
}
/*
* Store it
*/
m_tb_window = (quint64)data.hwnd;
return true;
}
/*
* Callback for the window enumaration pid find.
*/
BOOL CALLBACK WindowCtrlWin::enumWindowsPidProc( HWND hwnd, LPARAM lParam )
{
auto& data = *reinterpret_cast<EnumWindowsPidProcData*>(lParam);
unsigned long pid = 0;
GetWindowThreadProcessId( hwnd, &pid );
if( data.pid != pid || !isMainWindow( hwnd ) )
{
return TRUE;
}
data.hwnd = hwnd;
return FALSE;
}
/*
* Check for main window
*/
BOOL WindowCtrlWin::isMainWindow( HWND hwnd )
{
return GetWindow( hwnd, GW_OWNER ) == nullptr && IsWindowVisible( hwnd );
}
/*
* Display the window elements
*/
void WindowCtrlWin::displayWindowElements( const QString& title )
{
findWindow( title );
for( quint64 win_id: getWinIds() )
{
emit signalConsole( QString( "Found: XID %1" ).arg( win_id ) );
}
}
/*
* Display the window elements
*/
void WindowCtrlWin::displayWindowElements( quint64 window )
{
emit signalConsole( QString( "Found: XID %1" ).arg( window ) );
}
/*
* Get the Thunderbird window ID
*/
quint64 WindowCtrlWin::getWinId()
{
return m_tb_window;
}
/*
* Get the Thunderbird window IDs
*/
QList< quint64 > WindowCtrlWin::getWinIds()
{
return m_tb_windows;
}
/*
* Intercept the minimize event
*/
void WindowCtrlWin::interceptMinimizeWindow()
{
m_hook = SetWinEventHook(
EVENT_OBJECT_LOCATIONCHANGE ,EVENT_OBJECT_LOCATIONCHANGE,
NULL,
handleWinEvent,
getPpid(), 0,
WINEVENT_OUTOFCONTEXT );
}
/*
* Remove the intercept hook
*/
void WindowCtrlWin::stopInterceptMinimizeWindow()
{
UnhookWinEvent( m_hook );
}
/*
* Hook callback
*/
void WindowCtrlWin::handleWinEvent( HWINEVENTHOOK hook, DWORD event, HWND hWnd,
LONG idObject, LONG idChild,
DWORD dwEventThread, DWORD dwmsEventTime )
{
Q_UNUSED( hook );
Q_UNUSED( idObject );
Q_UNUSED( idChild );
Q_UNUSED( dwEventThread );
Q_UNUSED( dwmsEventTime );
if( EVENT_OBJECT_LOCATIONCHANGE == event )
{
WINDOWPLACEMENT wp;
wp.length = sizeof( WINDOWPLACEMENT );
GetWindowPlacement( hWnd, &wp );
if( SW_SHOWMINIMIZED == wp.showCmd )
{
/*
* Window is minimized
*/
if( m_ctrl_parent )
{
m_ctrl_parent->hookAction();
}
}
}
}
/*
* Non-static method to use by the hook callback
*/
void WindowCtrlWin::hookAction()
{
if( getWindowState() == "normal" && getMinimizeType() > 0 )
{
setWindowState( "minimized" );
/*
* Hide to tray
*/
hideWindow( (HWND)getWinId() );
}
}
/*
* Minimize a window
*/
void WindowCtrlWin::minimizeWindow( quint64 window, int hide )
{
if( !isThunderbird( getPpid() ) )
{
return;
}
ShowWindow( (HWND)window, SW_MINIMIZE );
if( hide )
{
hideWindow( (HWND)window );
}
}
/*
* Normalize a window
*/
void WindowCtrlWin::normalizeWindow( quint64 window )
{
if( !isThunderbird( getPpid() ) )
{
return;
}
ShowWindow( (HWND)window, SW_RESTORE );
SetForegroundWindow( (HWND)window );
}
/*
* Hide a window
*/
void WindowCtrlWin::hideWindow( quint64 window, bool state )
{
if( !isThunderbird( getPpid() ) )
{
return;
}
if( state )
{
hideWindow( (HWND)window );
}
}
/*
* Hide a window
*/
void WindowCtrlWin::hideWindow( HWND hwnd )
{
long style = GetWindowLong( hwnd, GWL_STYLE );
style &= ~(WS_VISIBLE);
style |= WS_EX_TOOLWINDOW;
style &= ~(WS_EX_APPWINDOW);
SetWindowLong( hwnd, GWL_STYLE, style );
}
/*
* Delete / Close a window
*/
void WindowCtrlWin::deleteWindow( quint64 window )
{
if( !isThunderbird( getPpid() ) )
{
return;
}
SendMessageA( (HWND)window, WM_CLOSE, 0, 0 );
}
#endif // Q_OS_WIN