From 5900687fa740b45f52a8dce17d1d7b42c78af55f Mon Sep 17 00:00:00 2001 From: Ximi1970 Date: Sun, 16 Feb 2020 22:24:17 +0100 Subject: [PATCH] Minimize / Normalize using X11 --- README.references.txt | 7 ++ app/SysTray-X/debugwidget.cpp | 10 ++ app/SysTray-X/debugwidget.h | 10 ++ app/SysTray-X/debugwidget.ui | 109 ++++++++++--------- app/SysTray-X/systrayx.cpp | 1 + app/SysTray-X/windowctrl-unix.cpp | 174 +++++++++++++++++++++++------- app/SysTray-X/windowctrl-unix.h | 46 ++++++++ app/SysTray-X/windowctrl.cpp | 41 +++++-- app/SysTray-X/windowctrl.h | 5 + 9 files changed, 304 insertions(+), 99 deletions(-) diff --git a/README.references.txt b/README.references.txt index 0af9da3..994058d 100644 --- a/README.references.txt +++ b/README.references.txt @@ -33,6 +33,13 @@ https://stackoverflow.com/questions/41622735/hide-window-from-linux-taskbar +minimize fullscreen Xlib OpenGL Window + +https://stackoverflow.com/questions/6381098/minimize-fullscreen-xlib-opengl-window + + + + Intercept close event X11 https://stackoverflow.com/questions/1157364/intercept-wm-delete-window-on-x11 diff --git a/app/SysTray-X/debugwidget.cpp b/app/SysTray-X/debugwidget.cpp index 7552ebf..6732984 100644 --- a/app/SysTray-X/debugwidget.cpp +++ b/app/SysTray-X/debugwidget.cpp @@ -32,6 +32,7 @@ DebugWidget::DebugWidget( Preferences* pref, QWidget* parent ) : QWidget( parent */ connect( m_ui->test1PushButton, &QPushButton::clicked, this, &DebugWidget::slotHandleTest1Button); connect( m_ui->test2PushButton, &QPushButton::clicked, this, &DebugWidget::slotHandleTest2Button); + connect( m_ui->test3PushButton, &QPushButton::clicked, this, &DebugWidget::slotHandleTest3Button); } @@ -158,6 +159,15 @@ void DebugWidget::slotHandleTest2Button() } +/* + * Handle test button 3 click + */ +void DebugWidget::slotHandleTest3Button() +{ + emit signalTest3ButtonClicked(); +} + + /* * Handle console signal */ diff --git a/app/SysTray-X/debugwidget.h b/app/SysTray-X/debugwidget.h index 2484a57..487396d 100644 --- a/app/SysTray-X/debugwidget.h +++ b/app/SysTray-X/debugwidget.h @@ -92,6 +92,11 @@ class DebugWidget : public QWidget */ void signalTest2ButtonClicked(); + /** + * @brief signalTestButton3Clicked. Signal the test button was clicked. + */ + void signalTest3ButtonClicked(); + public slots: /** @@ -144,6 +149,11 @@ class DebugWidget : public QWidget */ void slotHandleTest2Button(); + /** + * @brief slotHandleTest2Button. Handle a click on the test button. + */ + void slotHandleTest3Button(); + /** * @brief slotConsole. Handle console signal. * diff --git a/app/SysTray-X/debugwidget.ui b/app/SysTray-X/debugwidget.ui index 4ee11e7..c79c9aa 100644 --- a/app/SysTray-X/debugwidget.ui +++ b/app/SysTray-X/debugwidget.ui @@ -19,51 +19,10 @@ 10 10 381 - 281 + 288 - - - - 0 - - - - - - - Test 1 - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - @@ -77,6 +36,29 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Test 2 + + + + + + @@ -84,13 +66,38 @@ - - - - - + + - Test 2 + + + + + + + + + + + + + + + Test 1 + + + + + + + 0 + + + + + + + @@ -101,10 +108,10 @@ - - + + - + Test 3 diff --git a/app/SysTray-X/systrayx.cpp b/app/SysTray-X/systrayx.cpp index 51768c5..4eb7e73 100644 --- a/app/SysTray-X/systrayx.cpp +++ b/app/SysTray-X/systrayx.cpp @@ -80,6 +80,7 @@ SysTrayX::SysTrayX( QObject *parent ) : QObject( parent ) connect( m_win_ctrl, &WindowCtrl::signalConsole, m_debug, &DebugWidget::slotConsole ); connect( m_debug, &DebugWidget::signalTest1ButtonClicked, m_win_ctrl, &WindowCtrl::slotWindowTest1 ); connect( m_debug, &DebugWidget::signalTest2ButtonClicked, m_win_ctrl, &WindowCtrl::slotWindowTest2 ); + connect( m_debug, &DebugWidget::signalTest3ButtonClicked, m_win_ctrl, &WindowCtrl::slotWindowTest3 ); /* * Connect preferences signals diff --git a/app/SysTray-X/windowctrl-unix.cpp b/app/SysTray-X/windowctrl-unix.cpp index 82fec48..93324f7 100644 --- a/app/SysTray-X/windowctrl-unix.cpp +++ b/app/SysTray-X/windowctrl-unix.cpp @@ -6,39 +6,29 @@ * System includes */ #include +#include + /* * Constructor */ WindowCtrlUnix::WindowCtrlUnix( QObject *parent ) : QObject( parent ) { - + /* + * Get the base display and window + */ + m_display = XOpenDisplay( ":0" ); + m_screen = 0; + m_root_window = XDefaultRootWindow( m_display ); } /* - * Get the X11 window list + * Get the Thunderbird window ID */ -QList< WindowCtrlUnix::WindowItem > WindowCtrlUnix::listXWindows( Display *display, Window window, int level ) +unsigned long WindowCtrlUnix::getWId() { - 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; + return m_tb_window; } @@ -47,14 +37,12 @@ QList< WindowCtrlUnix::WindowItem > WindowCtrlUnix::listXWindows( Display *dis */ bool WindowCtrlUnix::findWindow( const QString& title, unsigned long& window ) { - Display *display = XOpenDisplay( ":0.0" ); - Window rootWindow = XDefaultRootWindow( display ); - QList< WindowItem > windows = listXWindows( display, rootWindow ); + QList< WindowItem > windows = listXWindows( m_display, m_root_window ); foreach( WindowItem win, windows ) { char *name = nullptr; - if( XFetchName( display, win.window, &name ) > 0 ) { + if( XFetchName( m_display, win.window, &name ) > 0 ) { QString win_name( name ); XFree( name ); @@ -63,17 +51,17 @@ bool WindowCtrlUnix::findWindow( const QString& title, unsigned long& window emit signalConsole( QString( "Found: Level %1, XID %2, Name %3" ).arg( win.level ).arg( win.window ).arg( win_name ) ); - QString name = atomName( display, win.window ); + QString name = atomName( m_display, win.window ); emit signalConsole( QString( "Atom name: %1" ).arg( name ) ); - QStringList types = atomWindowType( display, win.window ); + QStringList types = atomWindowType( m_display, win.window ); foreach( QString type, types ) { emit signalConsole( QString( "Atom type: %1" ).arg( type ) ); } - QStringList states = atomState( display, win.window ); + QStringList states = atomState( m_display, win.window ); bool max_vert = false; bool max_horz = false; @@ -129,8 +117,9 @@ bool WindowCtrlUnix::findWindow( const QString& title, unsigned long& window } /* - * Return the XID + * Store and return the XID */ + m_tb_window = win.window; window = win.window; return true; @@ -147,12 +136,10 @@ bool WindowCtrlUnix::findWindow( const QString& title, unsigned long& window */ void WindowCtrlUnix::findWindow( pid_t pid ) { - Display *display = XOpenDisplay( ":0.0" ); - Window rootWindow = XDefaultRootWindow( display ); - QList< WindowItem > windows = listXWindows( display, rootWindow ); + QList< WindowItem > windows = listXWindows( m_display, m_root_window ); // Get the PID property atom. - Atom atom_PID = XInternAtom( display, "_NET_WM_PID", True ); + Atom atom_PID = XInternAtom( m_display, "_NET_WM_PID", True ); if( atom_PID == None ) { emit signalConsole( QString( "No such atom _NET_WM_PID" ) ); @@ -166,7 +153,7 @@ void WindowCtrlUnix::findWindow( pid_t pid ) unsigned long bytesAfter; unsigned char* propPID = nullptr; - if( Success == XGetWindowProperty( display, win.window, atom_PID, 0, 1, False, XA_CARDINAL, + if( Success == XGetWindowProperty( m_display, win.window, atom_PID, 0, 1, False, XA_CARDINAL, &type, &format, &nItems, &bytesAfter, &propPID ) ) { if( propPID != nullptr ) @@ -174,21 +161,21 @@ void WindowCtrlUnix::findWindow( pid_t pid ) if( pid == *((reinterpret_cast( propPID ) ) ) ) { char* name = nullptr; - XFetchName( display, win.window, &name ); + XFetchName( m_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 = atomName( display, win.window ); + QString atom_name = atomName( m_display, win.window ); emit signalConsole( QString( "Atom Name %1" ).arg( atom_name ) ); - QStringList states = atomState( display, win.window ); + QStringList states = atomState( m_display, win.window ); foreach( QString state, states ) { emit signalConsole( QString( "Atom state: %1" ).arg( state ) ); } - QStringList types = atomWindowType( display, win.window ); + QStringList types = atomWindowType( m_display, win.window ); foreach( QString type, types ) { emit signalConsole( QString( "Atom type: %1" ).arg( type ) ); @@ -210,6 +197,117 @@ void WindowCtrlUnix::findWindow( pid_t pid ) } +/* + * Minimize a window + */ +void WindowCtrlUnix::minimizeWindow( Window window ) +{ + XIconifyWindow( m_display, window, m_screen ); + XFlush( m_display ); +} + + +/* + * Normalize a window + */ +void WindowCtrlUnix::normalizeWindow( Window window ) +{ +// XMapRaised( m_display, m_tb_window ); + XMapWindow( m_display, window ); + XFlush( m_display ); +} + + +#ifdef RAW_EVENT_SEND + +bool WindowCtrlUnix::generateEvent() +{ + XClientMessageEvent event; + Atom prop; + + prop = XInternAtom( m_display, "WM_CHANGE_STATE", False ); + if( prop == None ) + { + return false; + } + + event.type = ClientMessage; + event.window = m_tb_window; + event.message_type = prop; + event.format = 32; + event.data.l[0] = IconicState; + return XSendEvent( m_display, m_root_window, False, + SubstructureRedirectMask|SubstructureNotifyMask, + reinterpret_cast( &event ) ); +} + +#endif + +#ifdef CHANGE_PROP + +void WindowCtrlUnix::setAtomState() +{ + char prop_name[] = "_NET_WM_STATE"; + Atom prop = XInternAtom( m_display, prop_name, True ); + Atom prop_hidden = XInternAtom( m_display, WindowStates[ STATE_HIDDEN ].toUtf8(), True ); + + Atom type; + int format; + unsigned long remain; + unsigned long len; + unsigned char* list = nullptr; + + QStringList states; + + if( XGetWindowProperty( m_display, m_tb_window, prop, 0, sizeof( Atom ), False, XA_ATOM, + &type, &format, &len, &remain, &list ) == Success ) + { + emit signalConsole( QString( "Atom state" ) ); + + if( XChangeProperty( m_display, m_tb_window, prop, XA_ATOM, format, PropModeAppend, reinterpret_cast( &prop_hidden ), 1 ) == Success ) + { + emit signalConsole( QString( "Atom state appended: %1" ).arg( WindowStates[ STATE_HIDDEN ] ) ); + } + + emit signalConsole( QString( "Atom state done" ) ); + } + + if( list ) + { + XFree( list ); + } + + XFlush( m_display ); +} +#endif + + +/* + * Get the X11 window list + */ +QList< WindowCtrlUnix::WindowItem > WindowCtrlUnix::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; +} + + /* * Get the title of the window */ diff --git a/app/SysTray-X/windowctrl-unix.h b/app/SysTray-X/windowctrl-unix.h index cf6e3a5..045e038 100644 --- a/app/SysTray-X/windowctrl-unix.h +++ b/app/SysTray-X/windowctrl-unix.h @@ -110,6 +110,13 @@ class WindowCtrlUnix : public QObject */ explicit WindowCtrlUnix( QObject *parent = nullptr ); + /** + * @brief getWId. Get the Thunderbird windows ID. + * + * @return The ID. + */ + unsigned long getWId(); + /** * @brief findWindow. Find window with title. * @@ -127,6 +134,23 @@ class WindowCtrlUnix : public QObject */ void findWindow( int pid ); + + void setAtomState(); + + /** + * @brief minimizeWindow. Minimize window. + * + * @param window The window. + */ + void minimizeWindow( Window window ); + + /** + * @brief normalizeWindow. Normalize window. + * + * @param window The window. + */ + void normalizeWindow( Window window ); + private: /** @@ -195,6 +219,28 @@ class WindowCtrlUnix : public QObject * @param message The message. */ void signalConsole( QString message ); + + private: + + /** + * @brief m_display. Pointer to the main display. + */ + Display* m_display; + + /** + * @brief m_screen. The screen number. + */ + int m_screen; + + /** + * @brief m_root_window. The root window. + */ + Window m_root_window; + + /** + * @brief m_tb_window. The Thunderbird window. + */ + Window m_tb_window; }; #endif // WINDOWCTRLUNIX_H diff --git a/app/SysTray-X/windowctrl.cpp b/app/SysTray-X/windowctrl.cpp index c46e084..d0b9c73 100644 --- a/app/SysTray-X/windowctrl.cpp +++ b/app/SysTray-X/windowctrl.cpp @@ -33,14 +33,14 @@ void WindowCtrl::slotWindowTest1() // Do something. -// unsigned long win_id; -// findWindow( "Debugging with Firefox Developer Tools - Mozilla Thunderbird", win_id ); + unsigned long win_id; + findWindow( "Debugging with Firefox Developer Tools - Mozilla Thunderbird", win_id ); // findWindow( "Mozilla Thunderbird", win_id ); // findWindow( 4313 ); - captureWindow( "Debugging with Firefox Developer Tools - Mozilla Thunderbird" ); +// captureWindow( "Debugging with Firefox Developer Tools - Mozilla Thunderbird" ); emit signalConsole("Test 1 done"); @@ -53,10 +53,36 @@ void WindowCtrl::slotWindowTest2() // Do something. + unsigned long win_id = getWId(); + minimizeWindow( win_id ); +// normalizeWindow( win_id ); + + /* + * Disconnect container? + */ +/* + m_tb_window->setParent( nullptr ); + + delete m_tb_container; + m_tb_container = nullptr; +*/ emit signalConsole("Test 2 done"); } +void WindowCtrl::slotWindowTest3() +{ + emit signalConsole("Test 3 started"); + + // Do something. + + unsigned long win_id = getWId(); + normalizeWindow( win_id ); + + emit signalConsole("Test 3 done"); +} + + // "Debugging with Firefox Developer Tools - Mozilla Thunderbird" bool WindowCtrl::captureWindow( const QString& title ) @@ -71,9 +97,9 @@ bool WindowCtrl::captureWindow( const QString& title ) * Wrap Thunderbird window */ m_tb_window = QWindow::fromWinId( WinId ); - m_tb_container = QWidget::createWindowContainer( m_tb_window ); + m_tb_window->parent(); -// container->hide(); + m_tb_container = QWidget::createWindowContainer( m_tb_window ); return true; } @@ -103,11 +129,6 @@ void WindowCtrl::slotShowHide() if( m_tb_container ) { m_tb_container->show(); - -// m_tb_window->setParent( nullptr ); - -// delete m_tb_container; -// m_tb_container = nullptr; } } else { m_state = "minimized"; diff --git a/app/SysTray-X/windowctrl.h b/app/SysTray-X/windowctrl.h index fb1be35..039df6e 100644 --- a/app/SysTray-X/windowctrl.h +++ b/app/SysTray-X/windowctrl.h @@ -60,6 +60,11 @@ class WindowCtrl : public QObject */ void slotWindowTest2(); + /** + * @brief slotWindowTest3. Start a test. + */ + void slotWindowTest3(); + /** * @brief slotWindowState. Handle the window state change signal. *