2019-02-07 19:15:25 +02:00
/*
* Copyright 2019 Michail Vourlakos < mvourlakos @ gmail . com >
*
* This file is part of Latte - Dock
*
* Latte - Dock is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
*
* Latte - Dock is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "windowstracker.h"
// local
# include "positioner.h"
# include "view.h"
# include "../lattecorona.h"
# include "../../liblatte2/types.h"
namespace Latte {
namespace ViewPart {
WindowsTracker : : WindowsTracker ( Latte : : View * parent )
: QObject ( parent ) ,
m_latteView ( parent )
{
qDebug ( ) < < " WindowsTracker creating... " ;
m_corona = qobject_cast < Latte : : Corona * > ( m_latteView - > corona ( ) ) ;
m_wm = m_corona - > wm ( ) ;
}
WindowsTracker : : ~ WindowsTracker ( )
{
qDebug ( ) < < " WindowsTracker removing... " ;
}
2019-02-07 20:24:52 +02:00
bool WindowsTracker : : activeWindowTouching ( ) const
{
return m_activeWindowIsTouchingFlag ;
}
void WindowsTracker : : setActiveWindowTouching ( bool activeTouching )
{
if ( m_activeWindowIsTouchingFlag = = activeTouching ) {
return ;
}
m_activeWindowIsTouchingFlag = activeTouching ;
emit activeWindowTouchingChanged ( ) ;
}
2019-02-16 10:24:40 +02:00
bool WindowsTracker : : existsWindowActive ( ) const
{
return m_windowIsActiveFlag ;
}
void WindowsTracker : : setExistsWindowActive ( bool windowActive )
{
if ( m_windowIsActiveFlag = = windowActive ) {
return ;
}
m_windowIsActiveFlag = windowActive ;
emit existsWindowActiveChanged ( ) ;
}
2019-02-07 19:15:25 +02:00
bool WindowsTracker : : existsWindowMaximized ( ) const
{
return m_windowIsMaximizedFlag ;
}
void WindowsTracker : : setExistsWindowMaximized ( bool windowMaximized )
{
if ( m_windowIsMaximizedFlag = = windowMaximized ) {
return ;
}
m_windowIsMaximizedFlag = windowMaximized ;
emit existsWindowMaximizedChanged ( ) ;
}
bool WindowsTracker : : existsWindowTouching ( ) const
{
return m_windowIsTouchingFlag ;
}
void WindowsTracker : : setExistsWindowTouching ( bool windowTouching )
{
if ( m_windowIsTouchingFlag = = windowTouching ) {
return ;
}
m_windowIsTouchingFlag = windowTouching ;
emit existsWindowTouchingChanged ( ) ;
}
2019-02-07 20:45:56 +02:00
SchemeColors * WindowsTracker : : activeWindowScheme ( ) const
{
return m_activeScheme ;
}
void WindowsTracker : : setActiveWindowScheme ( SchemeColors * scheme )
{
if ( m_activeScheme = = scheme ) {
return ;
}
m_activeScheme = scheme ;
emit activeWindowSchemeChanged ( ) ;
}
2019-02-07 19:15:25 +02:00
SchemeColors * WindowsTracker : : touchingWindowScheme ( ) const
{
return m_touchingScheme ;
}
void WindowsTracker : : setTouchingWindowScheme ( SchemeColors * scheme )
{
if ( m_touchingScheme = = scheme ) {
return ;
}
m_touchingScheme = scheme ;
emit touchingWindowSchemeChanged ( ) ;
}
bool WindowsTracker : : enabled ( ) const
{
return m_enabled ;
}
void WindowsTracker : : setEnabled ( bool active )
{
if ( m_enabled = = active ) {
return ;
}
m_enabled = active ;
if ( m_enabled ) {
m_windows . clear ( ) ;
for ( const auto & wid : m_wm - > windows ( ) ) {
m_windows . insert ( wid , m_wm - > requestInfo ( wid ) ) ;
}
m_connections [ 0 ] = connect ( m_corona , & Plasma : : Corona : : availableScreenRectChanged ,
this , & WindowsTracker : : updateAvailableScreenGeometry ) ;
m_connections [ 1 ] = connect ( m_wm , & WindowSystem : : windowChanged , this , [ & ] ( WindowId wid ) {
m_windows [ wid ] = m_wm - > requestInfo ( wid ) ;
updateFlags ( ) ;
} ) ;
m_connections [ 2 ] = connect ( m_wm , & WindowSystem : : windowRemoved , this , [ & ] ( WindowId wid ) {
m_windows . remove ( wid ) ;
} ) ;
m_connections [ 3 ] = connect ( m_wm , & WindowSystem : : windowAdded , this , [ & ] ( WindowId wid ) {
m_windows . insert ( wid , m_wm - > requestInfo ( wid ) ) ;
updateFlags ( ) ;
} ) ;
m_connections [ 4 ] = connect ( m_wm , & WindowSystem : : activeWindowChanged , this , [ & ] ( WindowId wid ) {
if ( m_windows . contains ( m_lastActiveWindowWid ) ) {
m_windows [ m_lastActiveWindowWid ] = m_wm - > requestInfo ( m_lastActiveWindowWid ) ;
}
m_windows [ wid ] = m_wm - > requestInfo ( wid ) ;
m_lastActiveWindowWid = wid ;
updateFlags ( ) ;
} ) ;
m_connections [ 5 ] = connect ( m_wm , & WindowSystem : : currentDesktopChanged , this , [ & ] {
updateFlags ( ) ;
} ) ;
m_connections [ 6 ] = connect ( m_wm , & WindowSystem : : currentActivityChanged , this , [ & ] {
updateFlags ( ) ;
} ) ;
updateAvailableScreenGeometry ( ) ;
updateFlags ( ) ;
} else {
// clear mode
for ( auto & c : m_connections ) {
disconnect ( c ) ;
}
m_windows . clear ( ) ;
2019-02-07 20:24:52 +02:00
setActiveWindowTouching ( false ) ;
setExistsWindowMaximized ( false ) ;
setExistsWindowTouching ( false ) ;
2019-02-07 19:15:25 +02:00
}
emit enabledChanged ( ) ;
}
void WindowsTracker : : updateAvailableScreenGeometry ( )
{
if ( ! m_latteView | | ! m_latteView - > containment ( ) ) {
return ;
}
int currentScrId = m_latteView - > positioner ( ) - > currentScreenId ( ) ;
QRect tempAvailableScreenGeometry = m_corona - > availableScreenRectWithCriteria ( currentScrId , { Types : : AlwaysVisible } , { } ) ;
if ( tempAvailableScreenGeometry ! = m_availableScreenGeometry ) {
m_availableScreenGeometry = tempAvailableScreenGeometry ;
updateFlags ( ) ;
}
}
void WindowsTracker : : updateFlags ( )
{
2019-02-07 20:45:56 +02:00
bool foundActive { false } ;
2019-02-07 20:24:52 +02:00
bool foundActiveTouch { false } ;
2019-02-07 19:15:25 +02:00
bool foundTouch { false } ;
bool foundMaximized { false } ;
//! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0),
//! maybe a garbage collector here is a good idea!!!
bool existsFaultyWindow { false } ;
2019-02-07 20:45:56 +02:00
2019-02-07 19:15:25 +02:00
WindowId maxWinId ;
2019-02-07 20:45:56 +02:00
WindowId activeWinId ;
2019-02-07 19:15:25 +02:00
WindowId touchWinId ;
2019-02-07 20:45:56 +02:00
WindowId activeTouchWinId ;
2019-02-07 19:15:25 +02:00
for ( const auto & winfo : m_windows ) {
2019-02-07 20:45:56 +02:00
if ( isActiveInCurrentScreen ( winfo ) ) {
foundActive = true ;
activeWinId = winfo . wid ( ) ;
}
2019-02-07 19:15:25 +02:00
if ( isMaximizedInCurrentScreen ( winfo ) ) {
foundMaximized = true ;
maxWinId = winfo . wid ( ) ;
}
2019-02-23 21:19:59 +02:00
if ( isTouchingViewEdge ( winfo ) | | isTouchingView ( winfo ) ) {
2019-02-07 20:24:52 +02:00
if ( winfo . isActive ( ) ) {
foundActiveTouch = true ;
activeTouchWinId = winfo . wid ( ) ;
} else {
foundTouch = true ;
touchWinId = winfo . wid ( ) ;
}
2019-02-07 19:15:25 +02:00
}
if ( ! existsFaultyWindow & & winfo . geometry ( ) = = QRect ( 0 , 0 , 0 , 0 ) ) {
existsFaultyWindow = true ;
}
//qDebug() << "window geometry ::: " << winfo.geometry();
}
if ( existsFaultyWindow ) {
cleanupFaultyWindows ( ) ;
}
2019-02-16 10:24:40 +02:00
setExistsWindowActive ( foundActive ) ;
2019-02-07 20:24:52 +02:00
setActiveWindowTouching ( foundActiveTouch ) ;
2019-02-07 19:15:25 +02:00
setExistsWindowMaximized ( foundMaximized ) ;
2019-02-07 20:34:07 +02:00
setExistsWindowTouching ( foundTouch | | foundActiveTouch ) ;
2019-02-07 19:15:25 +02:00
2019-02-07 20:45:56 +02:00
//! update color schemes for active and touching windows
setActiveWindowScheme ( foundActive ? m_wm - > schemeForWindow ( activeWinId ) : nullptr ) ;
2019-02-07 19:15:25 +02:00
2019-02-07 20:24:52 +02:00
if ( foundActiveTouch ) {
setTouchingWindowScheme ( m_wm - > schemeForWindow ( activeTouchWinId ) ) ;
2019-02-07 19:15:25 +02:00
} else if ( foundMaximized ) {
setTouchingWindowScheme ( m_wm - > schemeForWindow ( maxWinId ) ) ;
2019-02-23 20:33:51 +02:00
} else if ( foundTouch ) {
setTouchingWindowScheme ( m_wm - > schemeForWindow ( touchWinId ) ) ;
2019-02-07 19:15:25 +02:00
} else {
setTouchingWindowScheme ( nullptr ) ;
}
}
2019-02-07 20:45:56 +02:00
bool WindowsTracker : : isActiveInCurrentScreen ( const WindowInfoWrap & winfo )
{
if ( winfo . isValid ( ) & & winfo . isActive ( ) & & ! winfo . isMinimized ( )
& & m_wm - > isOnCurrentDesktop ( winfo . wid ( ) ) & & m_wm - > isOnCurrentActivity ( winfo . wid ( ) )
& & m_availableScreenGeometry . contains ( winfo . geometry ( ) . center ( ) ) ) {
return true ;
}
return false ;
}
2019-02-07 19:15:25 +02:00
bool WindowsTracker : : isMaximizedInCurrentScreen ( const WindowInfoWrap & winfo )
{
//! updated implementation to identify the screen that the maximized window is present
//! in order to avoid: https://bugs.kde.org/show_bug.cgi?id=397700
if ( winfo . isValid ( ) & & ! winfo . isMinimized ( ) & & m_wm - > isOnCurrentDesktop ( winfo . wid ( ) ) & & m_wm - > isOnCurrentActivity ( winfo . wid ( ) ) ) {
if ( winfo . isMaximized ( ) & & m_availableScreenGeometry . contains ( winfo . geometry ( ) . center ( ) ) ) {
return true ;
}
}
return false ;
}
2019-02-23 21:19:59 +02:00
bool WindowsTracker : : isTouchingView ( const WindowInfoWrap & winfo )
2019-02-07 19:15:25 +02:00
{
if ( winfo . isValid ( ) & & ! winfo . isMinimized ( ) & & m_wm - > isOnCurrentDesktop ( winfo . wid ( ) ) & & m_wm - > isOnCurrentActivity ( winfo . wid ( ) ) ) {
2019-02-23 21:19:59 +02:00
return m_latteView - > visibility ( ) - > intersects ( winfo ) ;
}
return false ;
}
bool WindowsTracker : : isTouchingViewEdge ( const WindowInfoWrap & winfo )
{
if ( winfo . isValid ( ) & & ! winfo . isMinimized ( ) & & m_wm - > isOnCurrentDesktop ( winfo . wid ( ) ) & & m_wm - > isOnCurrentActivity ( winfo . wid ( ) ) ) {
bool touchingViewEdge { false } ;
2019-02-07 19:15:25 +02:00
QRect screenGeometry = m_latteView - > screenGeometry ( ) ;
bool inCurrentScreen { screenGeometry . contains ( winfo . geometry ( ) . topLeft ( ) ) | | screenGeometry . contains ( winfo . geometry ( ) . bottomRight ( ) ) } ;
if ( inCurrentScreen ) {
if ( m_latteView - > location ( ) = = Plasma : : Types : : TopEdge ) {
2019-02-23 21:19:59 +02:00
touchingViewEdge = ( winfo . geometry ( ) . y ( ) = = m_availableScreenGeometry . y ( ) ) ;
2019-02-07 19:15:25 +02:00
} else if ( m_latteView - > location ( ) = = Plasma : : Types : : BottomEdge ) {
2019-02-23 21:19:59 +02:00
touchingViewEdge = ( winfo . geometry ( ) . bottom ( ) = = m_availableScreenGeometry . bottom ( ) ) ;
2019-02-07 19:15:25 +02:00
} else if ( m_latteView - > location ( ) = = Plasma : : Types : : LeftEdge ) {
2019-02-23 21:19:59 +02:00
touchingViewEdge = ( winfo . geometry ( ) . x ( ) = = m_availableScreenGeometry . x ( ) ) ;
2019-02-07 19:15:25 +02:00
} else if ( m_latteView - > location ( ) = = Plasma : : Types : : RightEdge ) {
2019-02-23 21:19:59 +02:00
touchingViewEdge = ( winfo . geometry ( ) . right ( ) = = m_availableScreenGeometry . right ( ) ) ;
2019-02-07 19:15:25 +02:00
}
}
2019-02-23 21:19:59 +02:00
return touchingViewEdge ;
2019-02-07 19:15:25 +02:00
}
return false ;
}
void WindowsTracker : : cleanupFaultyWindows ( )
{
foreach ( auto key , m_windows . keys ( ) ) {
auto winfo = m_windows [ key ] ;
//! garbage windows removing
if ( winfo . geometry ( ) = = QRect ( 0 , 0 , 0 , 0 ) ) {
//qDebug() << "Faulty Geometry ::: " << winfo.wid();
m_windows . remove ( key ) ;
}
}
}
//! Window Functions
void WindowsTracker : : setWindowOnActivities ( QWindow & window , const QStringList & activities )
{
m_wm - > setWindowOnActivities ( window , activities ) ;
}
void WindowsTracker : : requestToggleMaximizeForActiveWindow ( )
{
WindowInfoWrap actInfo = m_wm - > requestInfoActive ( ) ;
//active window can be toggled only when it is in the same screen
if ( actInfo . isValid ( ) & & ! actInfo . geometry ( ) . isNull ( ) & & m_latteView - > screenGeometry ( ) . contains ( actInfo . geometry ( ) . center ( ) ) ) {
m_wm - > requestToggleMaximized ( actInfo . wid ( ) ) ;
}
}
void WindowsTracker : : requestMoveActiveWindow ( int localX , int localY )
{
WindowInfoWrap actInfo = m_wm - > requestInfoActive ( ) ;
//active window can be dragged only when it is in the same screen
if ( actInfo . isValid ( ) & & ! actInfo . geometry ( ) . isNull ( ) & & m_latteView - > screenGeometry ( ) . contains ( actInfo . geometry ( ) . center ( ) ) ) {
QPoint globalPoint { m_latteView - > x ( ) + localX , m_latteView - > y ( ) + localY } ;
m_wm - > requestMoveWindow ( actInfo . wid ( ) , globalPoint ) ;
//! This timer is needed because otherwise the mouse position
//! in the dragged window changes to TopLeft corner
QTimer : : singleShot ( 250 , this , [ & , actInfo , globalPoint ] ( ) {
m_wm - > releaseMouseEventFor ( m_latteView - > winId ( ) ) ;
} ) ;
2019-02-07 19:32:29 +02:00
m_latteView - > visibility ( ) - > activeWindowDraggingStarted ( ) ;
2019-02-07 19:15:25 +02:00
}
}
bool WindowsTracker : : activeWindowCanBeDragged ( )
{
WindowInfoWrap actInfo = m_wm - > requestInfoActive ( ) ;
//active window can be dragged only when it is in the same screen
if ( actInfo . isValid ( ) & & ! actInfo . geometry ( ) . isNull ( ) & & m_latteView - > screenGeometry ( ) . contains ( actInfo . geometry ( ) . center ( ) ) ) {
return m_wm - > windowCanBeDragged ( actInfo . wid ( ) ) ;
}
return false ;
}
}
}