Add debug and experimental X11 window methods

This commit is contained in:
Ximi1970
2020-02-16 13:38:23 +01:00
parent 8e4aeb58d1
commit 3aa9e9a7c1
12 changed files with 645 additions and 44 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
*.xpi
SysTray-X

View File

@@ -1,3 +1,62 @@
#<script>
X11
==========================================
Bash
xwininfo -tree -root
How to get the list of open windows from xserver
https://stackoverflow.com/questions/252906/how-to-get-the-list-of-open-windows-from-xserver
-> XQueryTree Xlib
https://tronche.com/gui/x/xlib/window-information/XQueryTree.html
https://stackoverflow.com/questions/11594184/getting-a-list-of-window-wids-in-qt
How to detect window state in linux?
https://stackoverflow.com/questions/37003959/how-to-detect-window-state-in-linux
Taskbar hide
https://stackoverflow.com/questions/41622735/hide-window-from-linux-taskbar
Intercept close event X11
https://stackoverflow.com/questions/1157364/intercept-wm-delete-window-on-x11
Qt X11
https://doc.qt.io/qt-5/qx11info.html
Obesolete X11 container qt4
https://stackoverflow.com/questions/39515384/qx11embedcontainer-alternative-in-qt5
Example container
https://stackoverflow.com/questions/1102658/qx11embedwidget-and-qx11embedcontainer
==========================================
Arguments for <script>
https://stackoverflow.com/questions/5292372/how-to-pass-parameters-to-a-script-tag

2
app/.gitignore vendored
View File

@@ -1 +1 @@
build-*
build*

View File

@@ -6,6 +6,10 @@
QT += core gui
unix: {
QT += x11extras
}
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = SysTray-X
@@ -30,6 +34,7 @@ CONFIG += c++11
#
unix:!macx: {
# QMAKE_LFLAGS += -lX11 -static-libgcc -static-libstdc++
QMAKE_LFLAGS += -lX11
}
win32: {
# QMAKE_LFLAGS += -static -lwinpthread -static-libgcc -static-libstdc++ $$(QMAKE_LFLAGS_WINDOWS)

View File

@@ -6,6 +6,10 @@
*/
#include "preferences.h"
/*
* System includes
*/
/*
* Qt includes
*/
@@ -22,6 +26,11 @@ DebugWidget::DebugWidget( Preferences* pref, QWidget* parent ) : QWidget( parent
* Store the preferences
*/
m_pref = pref;
/*
* Connect the button
*/
connect( m_ui->testPushButton, &QPushButton::clicked, this, &DebugWidget::slotHandleTestButton);
}
@@ -128,3 +137,21 @@ void DebugWidget::slotReceiveError( const QString& error )
{
setError( error );
}
/*
* Handle test button click
*/
void DebugWidget::slotHandleTestButton()
{
emit signalTestButtonClicked();
}
/*
* Handle console signal
*/
void DebugWidget::slotConsole( QString message )
{
m_ui->textEdit->append( message );
}

View File

@@ -43,35 +43,35 @@ class DebugWidget : public QWidget
*
* @param message The message to display.
*/
void setDebugMessage( const QString& message );
void setDebugMessage( const QString& message );
/**
* @brief setRawDataLength. Display the error data length.
*
* @param length The raw data length.
*/
void setRawDataLength( int length );
void setRawDataLength( int length );
/**
* @brief setRswDataMessage. Display the raw data.
*
* @param message The raw data messsage.
*/
void setErrorDataMessage( const QString &message );
void setErrorDataMessage( const QString &message );
/**
* @brief setUnreadMail. Set the number of unread mails.
*
* @param unread The number of unread mails.
*/
void setUnreadMail( int unread );
void setUnreadMail( int unread );
/**
* @brief setError. Set the error message.
*
* @param error The error message.
*/
void setError( const QString &error );
void setError( const QString &error );
signals:
@@ -80,49 +80,66 @@ class DebugWidget : public QWidget
*
* @param message
*/
void signalWriteMessage( const QByteArray& message );
void signalWriteMessage( const QByteArray& message );
/**
* @brief signalTestButtonClicked. Signal the test button was clicked.
*/
void signalTestButtonClicked();
public slots:
/**
* @brief slotDebugChange. The debug state changed.
*/
void slotDebugChange();
void slotDebugChange();
/**
* @brief slotDebugMessage
*
* @param message
*/
void slotDebugMessage( const QString& message );
void slotDebugMessage( const QString& message );
/**
* @brief slotReceivedDataLength. The received data length.
*
* @param data_len The received data length.
*/
void slotReceivedDataLength( qint32 msglen );
void slotReceivedDataLength( qint32 msglen );
/**
* @brief slotReceivedData. The received data.
*
* @param data The received data.
*/
void slotReceivedData( const QByteArray& data );
void slotReceivedData( const QByteArray& data );
/**
* @brief slotSetUnreadMail. Slot for handling unread mail signals.
*
* @param unread_mail The number of unread mails.
*/
void slotUnreadMail( int unread_mail );
void slotUnreadMail( int unread_mail );
/**
* @brief slotReceiveError. Handle receive error signal.
*
* @param error Error message.
*/
void slotReceiveError( const QString& error );
void slotReceiveError( const QString& error );
/**
* @brief slotHandleTestButton. Handle a click on the test button.
*/
void slotHandleTestButton();
/**
* @brief slotConsole. Handle console signal.
*
* @param message The message for the console.
*/
void slotConsole( QString message );
private:

View File

@@ -23,37 +23,24 @@
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="rawDataLengthLabel">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="errorLabel">
<item row="7" column="0">
<widget class="QPushButton" name="testPushButton">
<property name="text">
<string/>
<string>Test</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QLabel" name="unreadMailLabel">
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="errorLabel">
<property name="text">
<string>0</string>
<string/>
</property>
</widget>
</item>
@@ -70,13 +57,40 @@
</property>
</spacer>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLabel" name="rawDataLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="messageLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="unreadMailLabel">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="unreadMailTextLabel">
<property name="text">
@@ -85,11 +99,7 @@
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="messageLabel">
<property name="text">
<string/>
</property>
</widget>
<widget class="QTextEdit" name="textEdit"/>
</item>
</layout>
</widget>

View File

@@ -77,6 +77,8 @@ SysTrayX::SysTrayX( QObject *parent ) : QObject( parent )
connect( m_link, &SysTrayXLink::signalDebugMessage, m_debug, &DebugWidget::slotDebugMessage );
connect( m_win_ctrl, &WindowCtrl::signalDebugMessage, m_debug, &DebugWidget::slotDebugMessage );
connect( m_win_ctrl, &WindowCtrl::signalConsole, m_debug, &DebugWidget::slotConsole);
connect( m_debug, &DebugWidget::signalTestButtonClicked, m_win_ctrl, &WindowCtrl::slotWindowTest);
/*
* Connect preferences signals

View File

@@ -2,6 +2,9 @@
#ifdef Q_OS_UNIX
//#include <QX11Info>
#include <X11/Xatom.h>
/*
* Constructor
*/
@@ -11,10 +14,321 @@ WindowCtrl::WindowCtrl(QObject *parent) : QObject(parent)
}
void WindowCtrl::slotWindowTest()
{
emit signalConsole("Test started");
// Do something.
findWindow( "- Mozilla Thunderbird" );
// findWindow( 4313 );
emit signalConsole("Test done");
}
/*
* Get the X11 window list
*/
QList< WindowCtrl::WindowItem > WindowCtrl::listXWindows( Display *display, Window window, int level )
{
Window root;
Window parent;
Window *children;
unsigned int childrenCount;
QList< WindowItem > windows;
if( XQueryTree( display, window, &root, &parent, &children, &childrenCount) )
{
for( unsigned int i = 0; i < childrenCount; ++i )
{
windows.append( WindowItem( children[ i ], level ) );
windows.append( listXWindows( display, children[ i ], level + 1) );
}
XFree( children );
}
return windows;
}
/*
* Find a window by title
*/
void WindowCtrl::findWindow( const QString& title )
{
Display *display = XOpenDisplay( ":0.0" );
Window rootWindow = XDefaultRootWindow( display );
QList< WindowItem > windows = listXWindows( display, rootWindow );
foreach( WindowItem win, windows )
{
char *name = nullptr;
if( XFetchName( display, win.window, &name ) > 0 ) {
QString win_name( name );
XFree( name );
if( win_name.contains( title, Qt::CaseInsensitive ) ) {
emit signalConsole( QString( "Found: Level %1, XID %2, Name %3" ).arg( win.level ).arg( win.window ).arg( win_name ) );
QStringList types = atomWindowType( display, win.window );
foreach( QString type, types )
{
emit signalConsole( QString( "Atom type: %1" ).arg( type ) );
}
QStringList states = atomState( display, win.window );
bool max_vert = false;
bool max_horz = false;
bool hidden = false;
foreach( QString state, states )
{
emit signalConsole( QString( "Atom state: %1" ).arg( state ) );
int state_code = WindowStates.indexOf( state ) ;
switch( state_code )
{
case STATE_MAXIMIZED_VERT:
{
max_vert = true;
break;
}
case STATE_MAXIMIZED_HORZ:
{
max_horz = true;
break;
}
case STATE_HIDDEN:
{
hidden = true;
break;
}
}
}
if( states.length() > 0 )
{
if( max_vert && max_horz )
{
emit signalConsole( "Window State: Maximize" );
}
else
if( hidden )
{
emit signalConsole( "Window State: Hidden" );
}
else
{
emit signalConsole( "Window State: Normal" );
}
}
else
{
emit signalConsole( "Window State: Unknown" );
}
}
}
}
}
/*
* Find a window by PID
*/
void WindowCtrl::findWindow( pid_t pid )
{
Display *display = XOpenDisplay( ":0.0" );
Window rootWindow = XDefaultRootWindow( display );
QList< WindowItem > windows = listXWindows( display, rootWindow );
// Get the PID property atom.
Atom atom_PID = XInternAtom( display, "_NET_WM_PID", True );
if( atom_PID == None )
{
emit signalConsole( QString( "No such atom _NET_WM_PID" ) );
}
foreach( WindowItem win, windows )
{
Atom type;
int format;
unsigned long nItems;
unsigned long bytesAfter;
unsigned char* propPID = nullptr;
if( Success == XGetWindowProperty( display, win.window, atom_PID, 0, 1, False, XA_CARDINAL,
&type, &format, &nItems, &bytesAfter, &propPID ) )
{
if( propPID != nullptr )
{
if( pid == *((reinterpret_cast<pid_t *>( propPID ) ) ) )
{
char* name = nullptr;
XFetchName( display, win.window, &name );
emit signalConsole( QString( "Found: Level %1, XID %2, Name %3" ).arg( win.level ).arg( win.window ).arg( name ) );
QString atom_name = atomwName( display, win.window );
emit signalConsole( QString( "Atom Name %1" ).arg( atom_name ) );
QStringList states = atomState( display, win.window );
foreach( QString state, states )
{
emit signalConsole( QString( "Atom state: %1" ).arg( state ) );
}
QStringList types = atomWindowType( display, win.window );
foreach( QString type, types )
{
emit signalConsole( QString( "Atom type: %1" ).arg( type ) );
}
/*
* Cleanup
*/
if( name != nullptr )
{
XFree( name );
}
}
XFree( propPID );
}
}
}
}
/*
* Get the title of the window
*/
QString WindowCtrl::atomwName( Display *display, Window window )
{
char prop_name[] = "_NET_WM_NAME";
Atom prop = XInternAtom( display, prop_name, True );
Atom type;
int format;
unsigned long remain;
unsigned long len;
unsigned char* list = nullptr;
QString name;
if( XGetWindowProperty( display, window, prop, 0, LONG_MAX, False, AnyPropertyType,
&type, &format, &len, &remain, &list ) == Success )
{
name = QString( reinterpret_cast<char*>( list ) );
}
if( list )
{
XFree( list );
}
return name;
}
/*
* Get the state of the window
*/
QStringList WindowCtrl::atomState( Display *display, Window window )
{
char prop_name[] = "_NET_WM_STATE";
Atom prop = XInternAtom( display, prop_name, True );
Atom type;
int format;
unsigned long remain;
unsigned long len;
unsigned char* list = nullptr;
QStringList states;
if( XGetWindowProperty( display, window, prop, 0, LONG_MAX, False, AnyPropertyType,
&type, &format, &len, &remain, &list ) == Success )
{
for( int i = 0; i < static_cast<int>( len ); ++i )
{
Atom tmp_atom = reinterpret_cast<Atom *>( list )[ i ];
char* atom_name = XGetAtomName( display, tmp_atom );
states.append( atom_name );
if( atom_name )
{
XFree( atom_name );
}
}
}
if( list )
{
XFree( list );
}
return states;
}
/*
* Get the type of the window
*/
QStringList WindowCtrl::atomWindowType( Display *display, Window window )
{
char prop_name[] = "_NET_WM_WINDOW_TYPE";
Atom prop = XInternAtom( display, prop_name, True );
Atom type;
int format;
unsigned long remain;
unsigned long len;
unsigned char* list = nullptr;
QStringList states;
if( XGetWindowProperty( display, window, prop, 0, LONG_MAX, False, AnyPropertyType,
&type, &format, &len, &remain, &list ) == Success )
{
for( int i = 0; i < static_cast<int>( len ); ++i )
{
Atom tmp_atom = reinterpret_cast<Atom *>( list )[ i ];
char* atom_name = XGetAtomName( display, tmp_atom );
states.append( atom_name );
if( atom_name )
{
XFree( atom_name );
}
}
}
if( list )
{
XFree( list );
}
return states;
}
/*
* Handle change in window state
*/
void WindowCtrl::slotWindowState( QString state )
void WindowCtrl::slotWindowState( QString state )
{
m_state = state;
@@ -25,7 +339,7 @@ void WindowCtrl::slotWindowState( QString state )
/*
* Handle show / hide signal
*/
void WindowCtrl::slotShowHide()
void WindowCtrl::slotShowHide()
{
if( m_state == "minimized" )
{

View File

@@ -4,12 +4,107 @@
#ifndef WINDOWCTRLLINUX_H
#define WINDOWCTRLLINUX_H
/*
* Local includes
*/
#include "preferences.h"
/*
* System includes
*/
#include <X11/Xlib.h>
/*
* Qt includes
*/
#include <QObject>
/**
* @brief The WindowCtrl class.
*/
class WindowCtrl : public QObject
{
Q_OBJECT
public:
/*
* Window types
*/
enum WindowType
{
TYPE_UNKNOWN = 0,
TYPE_DESKTOP,
TYPE_DOCK,
TYPE_TOOLBAR,
TYPE_MENU,
TYPE_UTILITY,
TYPE_SPLASH,
TYPE_DIALOG,
TYPE_DROPDOWN_MENU,
TYPE_POPUP_MENU,
TYPE_TOOLTIP,
TYPE_NOTIFICATION,
TYPE_COMBO,
TYPE_DND,
TYPE_NORMAL
};
/*
* Window states
*/
enum WindowState
{
STATE_MODAL = 0,
STATE_STICKY,
STATE_MAXIMIZED_VERT,
STATE_MAXIMIZED_HORZ,
STATE_SHADED,
STATE_SKIP_TASKBAR,
STATE_SKIP_PAGER,
STATE_HIDDEN,
STATE_FULLSCREEN,
STATE_ABOVE,
STATE_BELOW,
STATE_DEMANDS_ATTENTION
};
const QStringList WindowStates = {
"_NET_WM_STATE_MODAL",
"_NET_WM_STATE_STICKY",
"_NET_WM_STATE_MAXIMIZED_VERT",
"_NET_WM_STATE_MAXIMIZED_HORZ",
"_NET_WM_STATE_SHADED",
"_NET_WM_STATE_SKIP_TASKBAR",
"_NET_WM_STATE_SKIP_PAGER",
"_NET_WM_STATE_HIDDEN",
"_NET_WM_STATE_FULLSCREEN",
"_NET_WM_STATE_ABOVE",
"_NET_WM_STATE_BELOW",
"_NET_WM_STATE_DEMANDS_ATTENTION"
};
/*
* Window list item
*/
class WindowItem
{
public:
WindowItem( Window win, int lev )
{
window = win;
level = lev;
}
Window window;
int level;
};
public:
/**
@@ -19,6 +114,63 @@ class WindowCtrl : public QObject
*/
explicit WindowCtrl( QObject *parent = nullptr );
/**
* @brief findWindow. Find window with title.
*
* @param title The title to find
*/
void findWindow( const QString& title );
/**
* @brief findWindow. Find window of a process.
*
* @param pid The process id.
*/
void findWindow( int pid );
private:
/**
* @brief listXWindows. Get all the windows.
*
* @param display The display.
* @param window The window.
* @param level The recursion level.
*
* @return The windows list.
*/
QList< WindowItem > listXWindows( Display* display, Window window, int level = 0 );
/**
* @brief atomwName. Get the title of the window.
*
* @param display The display
* @param window The window
*
* @return Name of the window.
*/
QString atomwName( Display *display, Window window );
/**
* @brief atomState. Get the state of the window.
*
* @param display The display
* @param window The window
*
* @return State of the window.
*/
QStringList atomState( Display *display, Window window );
/**
* @brief atomType. Get the type of the window.
*
* @param display The display
* @param window The window
*
* @return Type of the window.
*/
QStringList atomWindowType( Display *display, Window window );
signals:
/**
@@ -26,17 +178,24 @@ class WindowCtrl : public QObject
*
* @param message The message.
*/
void signalDebugMessage( QString message );
void signalDebugMessage( QString message );
/**
* @brief signalWindowNormal. Signal normal window.
*/
void signalWindowNormal();
void signalWindowNormal();
/**
* @brief signalWindowMinimuze. Signal minimize window.
*/
void signalWindowMinimize();
void signalWindowMinimize();
/**
* @brief signalConsole. Send a console message.
*
* @param message The message.
*/
void signalConsole( QString message );
public slots:
@@ -52,6 +211,11 @@ class WindowCtrl : public QObject
*/
void slotShowHide();
/**
* @brief slotWindowTest. Start a test.
*/
void slotWindowTest();
private:
/**

1
app/config/linux/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.json

1
app/config/win32/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.json