2016-12-25 10:25:27 +03:00
/*
2017-03-08 00:26:09 +03:00
* Copyright 2016 Smith AR < audoban @ openmaibox . org >
2017-01-03 01:05:30 +03:00
* 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/>.
*/
2016-12-25 10:25:27 +03:00
2016-12-31 00:25:27 +03:00
# include "dockcorona.h"
2018-02-03 12:34:13 +03:00
2017-02-15 07:54:41 +03:00
# include "alternativeshelper.h"
2018-02-03 12:34:13 +03:00
# include "globalshortcuts.h"
# include "importer.h"
# include "launcherssignals.h"
# include "layoutmanager.h"
2018-10-26 23:36:40 +03:00
# include "plasmathemeextended.h"
2017-02-24 21:58:21 +03:00
# include "screenpool.h"
2018-02-03 12:34:13 +03:00
# include "dock/dockview.h"
# include "packageplugins/shell/dockpackage.h"
2018-12-02 02:21:34 +03:00
# include "settings/universalsettings.h"
2018-12-02 02:29:18 +03:00
# include "wm/abstractwindowinterface.h"
# include "wm/waylandinterface.h"
# include "wm/xwindowinterface.h"
2018-02-03 12:34:13 +03:00
2017-03-11 11:06:10 +03:00
//dbus adaptor
# include "lattedockadaptor.h"
2016-12-25 10:25:27 +03:00
# include <QAction>
2017-02-26 03:43:41 +03:00
# include <QApplication>
2016-12-25 10:25:27 +03:00
# include <QScreen>
2017-03-11 11:06:10 +03:00
# include <QDBusConnection>
2016-12-25 10:25:27 +03:00
# include <QDebug>
2017-02-26 03:43:41 +03:00
# include <QDesktopWidget>
2017-07-25 00:01:41 +03:00
# include <QFile>
2017-04-21 16:59:58 +03:00
# include <QFontDatabase>
2017-02-15 07:54:41 +03:00
# include <QQmlContext>
2016-12-25 10:25:27 +03:00
# include <Plasma>
# include <Plasma/Corona>
# include <Plasma/Containment>
2017-04-06 20:00:48 +03:00
2018-02-03 23:19:35 +03:00
# include <PlasmaQuick/ConfigView>
2016-12-31 00:25:27 +03:00
# include <KActionCollection>
# include <KPluginMetaData>
2017-04-06 20:00:48 +03:00
# include <KGlobalAccel>
2016-12-25 10:25:27 +03:00
# include <KLocalizedString>
# include <KPackage/Package>
# include <KPackage/PackageLoader>
2017-01-29 08:16:28 +03:00
# include <KAboutData>
2017-02-15 07:54:41 +03:00
# include <KActivities/Consumer>
2018-02-03 23:19:35 +03:00
# include <KDeclarative/QmlObject>
2017-01-07 16:27:26 +03:00
2017-04-25 19:18:49 +03:00
# include <KWindowSystem>
# include <KWayland/Client/connection_thread.h>
# include <KWayland/Client/registry.h>
# include <KWayland/Client/plasmashell.h>
2018-03-02 00:53:28 +03:00
# include <KWayland/Client/plasmawindowmanagement.h>
2017-04-25 19:18:49 +03:00
2016-12-30 10:20:06 +03:00
namespace Latte {
2018-01-31 16:27:58 +03:00
DockCorona : : DockCorona ( bool defaultLayoutOnStartup , QString layoutNameOnStartUp , int userSetMemoryUsage , QObject * parent )
2017-01-07 16:27:26 +03:00
: Plasma : : Corona ( parent ) ,
2017-12-17 18:42:49 +03:00
m_defaultLayoutOnStartup ( defaultLayoutOnStartup ) ,
2018-01-31 16:27:58 +03:00
m_userSetMemoryUsage ( userSetMemoryUsage ) ,
2017-12-17 19:34:50 +03:00
m_layoutNameOnStartUp ( layoutNameOnStartUp ) ,
2017-04-02 08:25:03 +03:00
m_activityConsumer ( new KActivities : : Consumer ( this ) ) ,
2017-02-24 21:58:21 +03:00
m_screenPool ( new ScreenPool ( KSharedConfig : : openConfig ( ) , this ) ) ,
2017-07-02 15:02:07 +03:00
m_globalShortcuts ( new GlobalShortcuts ( this ) ) ,
2017-07-02 16:12:58 +03:00
m_universalSettings ( new UniversalSettings ( KSharedConfig : : openConfig ( ) , this ) ) ,
2018-10-26 23:36:40 +03:00
m_themeExtended ( new PlasmaThemeExtended ( KSharedConfig : : openConfig ( ) , this ) ) ,
2017-07-02 15:02:07 +03:00
m_layoutManager ( new LayoutManager ( this ) )
2016-12-25 10:25:27 +03:00
{
2018-03-02 00:53:28 +03:00
//! create the window manager
if ( KWindowSystem : : isPlatformWayland ( ) ) {
m_wm = new WaylandInterface ( this ) ;
} else {
m_wm = new XWindowInterface ( this ) ;
}
2017-04-25 19:18:49 +03:00
setupWaylandIntegration ( ) ;
2016-12-31 00:25:27 +03:00
KPackage : : Package package ( new DockPackage ( this ) ) ;
2018-10-27 00:59:36 +03:00
2017-02-26 21:06:31 +03:00
m_screenPool - > load ( ) ;
2017-01-16 22:07:49 +03:00
2016-12-25 10:25:27 +03:00
if ( ! package . isValid ( ) ) {
qWarning ( ) < < staticMetaObject . className ( )
< < " the package " < < package . metadata ( ) . rawData ( ) < < " is invalid! " ;
return ;
} else {
qDebug ( ) < < staticMetaObject . className ( )
< < " the package " < < package . metadata ( ) . rawData ( ) < < " is valid! " ;
}
2017-01-16 22:07:49 +03:00
2016-12-25 10:25:27 +03:00
setKPackage ( package ) ;
2018-10-27 00:59:36 +03:00
//! universal settings / extendedtheme must be loaded after the package has been set
2017-07-03 10:41:59 +03:00
m_universalSettings - > load ( ) ;
2018-10-27 00:59:36 +03:00
m_themeExtended - > load ( ) ;
2017-04-23 22:34:29 +03:00
2016-12-25 10:25:27 +03:00
qmlRegisterTypes ( ) ;
2017-04-21 16:59:58 +03:00
2017-01-24 21:32:22 +03:00
if ( m_activityConsumer & & ( m_activityConsumer - > serviceStatus ( ) = = KActivities : : Consumer : : Running ) ) {
load ( ) ;
}
2017-01-07 16:27:26 +03:00
connect ( m_activityConsumer , & KActivities : : Consumer : : serviceStatusChanged , this , & DockCorona : : load ) ;
2017-03-01 21:49:21 +03:00
m_docksScreenSyncTimer . setSingleShot ( true ) ;
2018-04-01 15:04:52 +03:00
m_docksScreenSyncTimer . setInterval ( m_universalSettings - > screenTrackerInterval ( ) ) ;
2018-01-07 14:50:27 +03:00
connect ( & m_docksScreenSyncTimer , & QTimer : : timeout , this , & DockCorona : : syncDockViewsToScreens ) ;
2018-04-01 15:04:52 +03:00
connect ( m_universalSettings , & UniversalSettings : : screenTrackerIntervalChanged , this , [ this ] ( ) {
m_docksScreenSyncTimer . setInterval ( m_universalSettings - > screenTrackerInterval ( ) ) ;
} ) ;
2017-03-11 11:06:10 +03:00
//! Dbus adaptor initialization
new LatteDockAdaptor ( this ) ;
QDBusConnection dbus = QDBusConnection : : sessionBus ( ) ;
dbus . registerObject ( QStringLiteral ( " /Latte " ) , this ) ;
2016-12-25 10:25:27 +03:00
}
2016-12-31 00:25:27 +03:00
DockCorona : : ~ DockCorona ( )
2016-12-25 10:25:27 +03:00
{
2018-02-03 16:44:37 +03:00
//! BEGIN: Give the time to slide-out docks when closing
m_layoutManager - > hideAllDocks ( ) ;
2018-08-30 08:47:53 +03:00
//! Don't delay the destruction under wayland in any case
2018-04-09 11:15:21 +03:00
//! because it creates a crash with kwin effects
//! https://bugs.kde.org/show_bug.cgi?id=392890
if ( ! KWindowSystem : : isPlatformWayland ( ) ) {
QTimer : : singleShot ( 400 , [ this ] ( ) {
m_quitTimedEnded = true ;
} ) ;
while ( ! m_quitTimedEnded ) {
QGuiApplication : : processEvents ( QEventLoop : : AllEvents , 50 ) ;
}
2018-02-03 16:44:37 +03:00
}
//! END: slide-out docks when closing
2017-03-01 21:49:21 +03:00
m_docksScreenSyncTimer . stop ( ) ;
2018-01-14 18:30:29 +03:00
if ( m_layoutManager - > memoryUsage ( ) = = Dock : : SingleLayout ) {
cleanConfig ( ) ;
}
2017-01-21 21:08:47 +03:00
2018-01-10 20:48:23 +03:00
qDebug ( ) < < " Latte Corona - unload: containments ... " ;
2017-06-26 22:16:42 +03:00
2018-01-13 04:08:32 +03:00
m_layoutManager - > unload ( ) ;
2017-01-16 22:07:49 +03:00
2018-03-02 00:53:28 +03:00
m_wm - > deleteLater ( ) ;
2017-06-04 01:58:03 +03:00
m_globalShortcuts - > deleteLater ( ) ;
2017-07-02 15:02:07 +03:00
m_layoutManager - > deleteLater ( ) ;
2018-01-08 20:21:34 +03:00
m_screenPool - > deleteLater ( ) ;
2017-07-02 15:02:07 +03:00
m_universalSettings - > deleteLater ( ) ;
2018-10-26 23:36:40 +03:00
m_themeExtended - > deleteLater ( ) ;
2017-06-04 01:58:03 +03:00
2017-01-07 16:27:26 +03:00
disconnect ( m_activityConsumer , & KActivities : : Consumer : : serviceStatusChanged , this , & DockCorona : : load ) ;
delete m_activityConsumer ;
2017-06-26 22:16:42 +03:00
2018-01-13 13:00:47 +03:00
qDebug ( ) < < " Latte Corona - deleted... " ;
2016-12-25 10:25:27 +03:00
}
2017-01-07 16:27:26 +03:00
void DockCorona : : load ( )
{
2017-01-24 21:32:22 +03:00
if ( m_activityConsumer & & ( m_activityConsumer - > serviceStatus ( ) = = KActivities : : Consumer : : Running ) & & m_activitiesStarting ) {
2017-02-24 21:58:21 +03:00
disconnect ( m_activityConsumer , & KActivities : : Consumer : : serviceStatusChanged , this , & DockCorona : : load ) ;
2017-07-23 21:05:34 +03:00
m_layoutManager - > load ( ) ;
2017-02-24 21:58:21 +03:00
2017-01-24 21:32:22 +03:00
m_activitiesStarting = false ;
2017-03-01 17:59:04 +03:00
2017-02-24 21:58:21 +03:00
connect ( qGuiApp , & QGuiApplication : : primaryScreenChanged , this , & DockCorona : : primaryOutputChanged , Qt : : UniqueConnection ) ;
2017-02-26 03:43:41 +03:00
connect ( QApplication : : desktop ( ) , & QDesktopWidget : : screenCountChanged , this , & DockCorona : : screenCountChanged ) ;
2018-02-03 16:44:37 +03:00
2017-02-26 03:43:41 +03:00
connect ( m_screenPool , & ScreenPool : : primaryPoolChanged , this , & DockCorona : : screenCountChanged ) ;
2017-02-24 21:58:21 +03:00
2017-07-23 21:05:34 +03:00
QString assignedLayout = m_layoutManager - > shouldSwitchToLayout ( m_activityConsumer - > currentActivity ( ) ) ;
2017-12-17 18:01:30 +03:00
QString loadLayoutName = " " ;
2017-12-17 19:34:50 +03:00
if ( ! m_defaultLayoutOnStartup & & m_layoutNameOnStartUp . isEmpty ( ) ) {
2017-12-17 18:42:49 +03:00
if ( ! assignedLayout . isEmpty ( ) & & assignedLayout ! = m_universalSettings - > currentLayoutName ( ) ) {
loadLayoutName = assignedLayout ;
} else {
loadLayoutName = m_universalSettings - > currentLayoutName ( ) ;
2017-12-17 18:01:30 +03:00
}
2017-12-17 18:42:49 +03:00
if ( ! m_layoutManager - > layoutExists ( loadLayoutName ) ) {
loadLayoutName = m_layoutManager - > defaultLayoutName ( ) ;
m_layoutManager - > importDefaultLayout ( false ) ;
}
2017-12-17 19:34:50 +03:00
} else if ( m_defaultLayoutOnStartup ) {
2017-12-17 18:42:49 +03:00
loadLayoutName = m_layoutManager - > importer ( ) - > uniqueLayoutName ( m_layoutManager - > defaultLayoutName ( ) ) ;
m_layoutManager - > importDefaultLayout ( true ) ;
2017-12-17 19:34:50 +03:00
} else {
loadLayoutName = m_layoutNameOnStartUp ;
2017-07-23 21:05:34 +03:00
}
2017-06-06 12:48:11 +03:00
2018-03-31 11:28:22 +03:00
if ( m_userSetMemoryUsage ! = - 1 & & ! KWindowSystem : : isPlatformWayland ( ) ) {
2018-01-31 16:27:58 +03:00
Dock : : LayoutsMemoryUsage usage = static_cast < Dock : : LayoutsMemoryUsage > ( m_userSetMemoryUsage ) ;
m_universalSettings - > setLayoutsMemoryUsage ( usage ) ;
}
2018-03-31 11:28:22 +03:00
if ( KWindowSystem : : isPlatformWayland ( ) ) {
m_universalSettings - > setLayoutsMemoryUsage ( Dock : : SingleLayout ) ;
}
2018-01-15 15:09:41 +03:00
m_layoutManager - > loadLayoutOnStartup ( loadLayoutName ) ;
2018-11-23 17:57:33 +03:00
//! load screens signals such screenGeometryChanged in order to support
//! plasmoid.screenGeometry properly
for ( QScreen * screen : qGuiApp - > screens ( ) ) {
addOutput ( screen ) ;
}
connect ( qGuiApp , & QGuiApplication : : screenAdded , this , & DockCorona : : addOutput , Qt : : UniqueConnection ) ;
2017-01-24 21:32:22 +03:00
}
2017-01-07 16:27:26 +03:00
}
2017-06-26 22:16:42 +03:00
void DockCorona : : unload ( )
{
2018-01-08 20:21:34 +03:00
qDebug ( ) < < " unload: removing containments... " ;
2017-06-26 22:16:42 +03:00
while ( ! containments ( ) . isEmpty ( ) ) {
//deleting a containment will remove it from the list due to QObject::destroyed connect in Corona
//this form doesn't crash, while qDeleteAll(containments()) does
delete containments ( ) . first ( ) ;
}
}
2017-04-25 19:18:49 +03:00
void DockCorona : : setupWaylandIntegration ( )
{
if ( ! KWindowSystem : : isPlatformWayland ( ) ) {
return ;
}
2018-03-01 01:52:05 +03:00
using namespace KWayland : : Client ;
2017-06-24 00:27:58 +03:00
auto connection = ConnectionThread : : fromApplication ( this ) ;
2017-04-25 19:18:49 +03:00
2018-03-01 01:52:05 +03:00
if ( ! connection ) {
2017-04-25 19:18:49 +03:00
return ;
2018-03-01 01:52:05 +03:00
}
2017-04-25 19:18:49 +03:00
2017-06-16 00:56:55 +03:00
Registry * registry { new Registry ( this ) } ;
2017-04-25 19:18:49 +03:00
registry - > create ( connection ) ;
2017-06-16 00:56:55 +03:00
connect ( registry , & Registry : : plasmaShellAnnounced , this
2017-07-03 10:41:59 +03:00
, [ this , registry ] ( quint32 name , quint32 version ) {
2017-04-25 19:18:49 +03:00
m_waylandDockCorona = registry - > createPlasmaShell ( name , version , this ) ;
2017-06-16 00:56:55 +03:00
} ) ;
2018-03-02 00:53:28 +03:00
QObject : : connect ( registry , & KWayland : : Client : : Registry : : plasmaWindowManagementAnnounced ,
[ this , registry ] ( quint32 name , quint32 version ) {
KWayland : : Client : : PlasmaWindowManagement * pwm = registry - > createPlasmaWindowManagement ( name , version , this ) ;
WaylandInterface * wI = qobject_cast < WaylandInterface * > ( m_wm ) ;
if ( wI ) {
wI - > initWindowManagement ( pwm ) ;
}
} ) ;
2017-04-25 19:18:49 +03:00
registry - > setup ( ) ;
2018-03-01 01:52:05 +03:00
connection - > roundtrip ( ) ;
2017-04-25 19:18:49 +03:00
}
KWayland : : Client : : PlasmaShell * DockCorona : : waylandDockCoronaInterface ( ) const
{
return m_waylandDockCorona ;
}
2017-01-21 21:08:47 +03:00
void DockCorona : : cleanConfig ( )
{
auto containmentsEntries = config ( ) - > group ( " Containments " ) ;
bool changed = false ;
2017-01-22 02:28:39 +03:00
foreach ( auto cId , containmentsEntries . groupList ( ) ) {
2017-02-06 04:55:41 +03:00
if ( ! containmentExists ( cId . toUInt ( ) ) ) {
2017-01-22 02:28:39 +03:00
//cleanup obsolete containments
containmentsEntries . group ( cId ) . deleteGroup ( ) ;
2017-01-21 21:08:47 +03:00
changed = true ;
2017-01-22 02:28:39 +03:00
qDebug ( ) < < " obsolete containment configuration deleted: " < < cId ;
} else {
//cleanup obsolete applets of running containments
auto appletsEntries = containmentsEntries . group ( cId ) . group ( " Applets " ) ;
foreach ( auto appletId , appletsEntries . groupList ( ) ) {
2017-02-06 04:55:41 +03:00
if ( ! appletExists ( cId . toUInt ( ) , appletId . toUInt ( ) ) ) {
2017-01-22 02:28:39 +03:00
appletsEntries . group ( appletId ) . deleteGroup ( ) ;
changed = true ;
qDebug ( ) < < " obsolete applet configuration deleted: " < < appletId ;
}
}
2017-01-21 21:08:47 +03:00
}
}
if ( changed ) {
config ( ) - > sync ( ) ;
qDebug ( ) < < " configuration file cleaned... " ;
}
}
2017-02-06 04:55:41 +03:00
bool DockCorona : : containmentExists ( uint id ) const
2017-01-21 21:08:47 +03:00
{
foreach ( auto containment , containments ( ) ) {
if ( id = = containment - > id ( ) ) {
return true ;
}
}
return false ;
}
2017-02-06 04:55:41 +03:00
bool DockCorona : : appletExists ( uint containmentId , uint appletId ) const
2017-01-22 02:28:39 +03:00
{
Plasma : : Containment * containment = nullptr ;
foreach ( auto cont , containments ( ) ) {
if ( containmentId = = cont - > id ( ) ) {
containment = cont ;
break ;
}
}
if ( ! containment ) {
return false ;
}
foreach ( auto applet , containment - > applets ( ) ) {
if ( applet - > id ( ) = = appletId ) {
return true ;
}
}
return false ;
}
2018-01-13 20:27:32 +03:00
KActivities : : Consumer * DockCorona : : activitiesConsumer ( ) const
{
return m_activityConsumer ;
}
2017-02-24 21:58:21 +03:00
ScreenPool * DockCorona : : screenPool ( ) const
{
return m_screenPool ;
}
2017-07-02 16:12:58 +03:00
UniversalSettings * DockCorona : : universalSettings ( ) const
{
return m_universalSettings ;
}
LayoutManager * DockCorona : : layoutManager ( ) const
{
return m_layoutManager ;
}
2018-03-02 00:53:28 +03:00
AbstractWindowInterface * DockCorona : : wm ( ) const
{
return m_wm ;
}
2018-10-26 23:36:40 +03:00
PlasmaThemeExtended * DockCorona : : themeExtended ( ) const
{
return m_themeExtended ;
}
2016-12-31 00:25:27 +03:00
int DockCorona : : numScreens ( ) const
2016-12-25 10:25:27 +03:00
{
return qGuiApp - > screens ( ) . count ( ) ;
}
2016-12-31 00:25:27 +03:00
QRect DockCorona : : screenGeometry ( int id ) const
2016-12-25 10:25:27 +03:00
{
const auto screens = qGuiApp - > screens ( ) ;
2017-04-04 14:39:17 +03:00
const QScreen * screen { qGuiApp - > primaryScreen ( ) } ;
QString screenName ;
if ( m_screenPool - > knownIds ( ) . contains ( id ) )
screenName = m_screenPool - > connector ( id ) ;
2017-01-16 22:07:49 +03:00
2017-04-04 14:39:17 +03:00
foreach ( auto scr , screens ) {
if ( scr - > name ( ) = = screenName ) {
screen = scr ;
break ;
}
2016-12-25 10:25:27 +03:00
}
2017-01-16 22:07:49 +03:00
2017-04-04 14:39:17 +03:00
return screen - > geometry ( ) ;
2016-12-25 10:25:27 +03:00
}
2016-12-31 00:25:27 +03:00
QRegion DockCorona : : availableScreenRegion ( int id ) const
2018-01-13 22:10:58 +03:00
{
return availableScreenRegionWithCriteria ( id ) ;
}
QRegion DockCorona : : availableScreenRegionWithCriteria ( int id , QString forLayout ) const
2016-12-25 10:25:27 +03:00
{
2017-03-02 23:10:26 +03:00
const auto screens = qGuiApp - > screens ( ) ;
const QScreen * screen { qGuiApp - > primaryScreen ( ) } ;
2017-03-20 20:00:28 +03:00
QString screenName ;
if ( m_screenPool - > knownIds ( ) . contains ( id ) )
screenName = m_screenPool - > connector ( id ) ;
2017-03-02 23:10:26 +03:00
foreach ( auto scr , screens ) {
2017-03-20 20:00:28 +03:00
if ( scr - > name ( ) = = screenName ) {
2017-03-02 23:10:26 +03:00
screen = scr ;
break ;
}
}
if ( ! screen )
return QRegion ( ) ;
2018-01-13 22:10:58 +03:00
QHash < const Plasma : : Containment * , DockView * > * views ;
if ( forLayout . isEmpty ( ) ) {
views = m_layoutManager - > currentDockViews ( ) ;
} else {
views = m_layoutManager - > layoutDockViews ( forLayout ) ;
}
2018-01-08 20:21:34 +03:00
2017-03-02 23:10:26 +03:00
QRegion available ( screen - > geometry ( ) ) ;
2018-01-14 18:30:29 +03:00
if ( views ) {
for ( const auto * view : * views ) {
if ( view & & view - > containment ( ) & & view - > screen ( ) = = screen
& & view - > visibility ( ) & & ( view - > visibility ( ) - > mode ( ) ! = Latte : : Dock : : AutoHide ) ) {
2018-12-01 01:52:05 +03:00
int realThickness = view - > normalThickness ( ) - view - > effects ( ) - > innerShadow ( ) ;
2018-01-14 18:30:29 +03:00
// Usually availableScreenRect is used by the desktop,
2018-08-30 08:47:53 +03:00
// but Latte don't have desktop, then here just
2018-01-14 18:30:29 +03:00
// need calculate available space for top and bottom location,
// because the left and right are those who dodge others docks
switch ( view - > location ( ) ) {
case Plasma : : Types : : TopEdge :
if ( view - > behaveAsPlasmaPanel ( ) ) {
available - = view - > geometry ( ) ;
} else {
QRect realGeometry ;
int realWidth = view - > maxLength ( ) * view - > width ( ) ;
switch ( view - > alignment ( ) ) {
case Latte : : Dock : : Left :
realGeometry = QRect ( view - > x ( ) , view - > y ( ) ,
realWidth , realThickness ) ;
break ;
case Latte : : Dock : : Center :
case Latte : : Dock : : Justify :
2018-07-03 22:15:45 +03:00
realGeometry = QRect ( qMax ( view - > geometry ( ) . x ( ) , view - > geometry ( ) . center ( ) . x ( ) - realWidth / 2 ) , view - > y ( ) ,
realWidth , realThickness ) ;
2018-01-14 18:30:29 +03:00
break ;
case Latte : : Dock : : Right :
realGeometry = QRect ( view - > geometry ( ) . right ( ) - realWidth + 1 , view - > y ( ) ,
realWidth , realThickness ) ;
break ;
}
available - = realGeometry ;
2017-07-03 10:41:59 +03:00
}
2018-01-14 18:30:29 +03:00
break ;
case Plasma : : Types : : BottomEdge :
if ( view - > behaveAsPlasmaPanel ( ) ) {
available - = view - > geometry ( ) ;
} else {
QRect realGeometry ;
int realWidth = view - > maxLength ( ) * view - > width ( ) ;
int realY = view - > geometry ( ) . bottom ( ) - realThickness + 1 ;
switch ( view - > alignment ( ) ) {
case Latte : : Dock : : Left :
realGeometry = QRect ( view - > x ( ) , realY ,
realWidth , realThickness ) ;
break ;
case Latte : : Dock : : Center :
case Latte : : Dock : : Justify :
realGeometry = QRect ( qMax ( view - > geometry ( ) . x ( ) , view - > geometry ( ) . center ( ) . x ( ) - realWidth / 2 ) ,
realY , realWidth , realThickness ) ;
break ;
case Latte : : Dock : : Right :
realGeometry = QRect ( view - > geometry ( ) . right ( ) - realWidth + 1 , realY ,
realWidth , realThickness ) ;
break ;
}
available - = realGeometry ;
2017-07-03 10:41:59 +03:00
}
2018-01-14 18:30:29 +03:00
break ;
2017-03-02 23:10:26 +03:00
2018-01-14 18:30:29 +03:00
default :
//! bypass clang warnings
break ;
}
2017-03-02 23:10:26 +03:00
}
}
}
/*qDebug() << "::::: FREE AREAS :::::";
2017-03-04 16:29:56 +03:00
2017-03-02 23:10:26 +03:00
for ( int i = 0 ; i < available . rectCount ( ) ; + + i ) {
qDebug ( ) < < available . rects ( ) . at ( i ) ;
}
2017-03-04 16:29:56 +03:00
2017-03-02 23:10:26 +03:00
qDebug ( ) < < " ::::: END OF FREE AREAS ::::: " ; */
return available ;
2016-12-25 10:25:27 +03:00
}
2016-12-31 00:25:27 +03:00
QRect DockCorona : : availableScreenRect ( int id ) const
2017-12-24 21:54:45 +03:00
{
2018-01-04 19:20:04 +03:00
return availableScreenRectWithCriteria ( id ) ;
2017-12-24 21:54:45 +03:00
}
2018-01-04 19:20:04 +03:00
QRect DockCorona : : availableScreenRectWithCriteria ( int id , QList < Dock : : Visibility > modes , QList < Plasma : : Types : : Location > edges ) const
2016-12-25 10:25:27 +03:00
{
const auto screens = qGuiApp - > screens ( ) ;
2017-03-01 21:22:23 +03:00
const QScreen * screen { qGuiApp - > primaryScreen ( ) } ;
2017-03-13 22:07:40 +03:00
if ( m_screenPool - > knownIds ( ) . contains ( id ) ) {
QString scrName = m_screenPool - > connector ( id ) ;
foreach ( auto scr , screens ) {
if ( scr - > name ( ) = = scrName ) {
screen = scr ;
break ;
}
2017-03-02 19:07:29 +03:00
}
2017-03-01 21:22:23 +03:00
}
2017-02-10 02:11:34 +03:00
2017-02-11 06:12:17 +03:00
if ( ! screen )
return { } ;
2017-01-16 22:07:49 +03:00
2018-01-04 19:20:04 +03:00
bool allModes = modes . isEmpty ( ) ;
bool allEdges = edges . isEmpty ( ) ;
2017-02-11 06:12:17 +03:00
auto available = screen - > geometry ( ) ;
2017-02-10 02:11:34 +03:00
2018-01-11 21:34:16 +03:00
QHash < const Plasma : : Containment * , DockView * > * views = m_layoutManager - > currentDockViews ( ) ;
2018-01-08 20:21:34 +03:00
2018-01-14 18:30:29 +03:00
if ( views ) {
for ( const auto * view : * views ) {
if ( view & & view - > containment ( ) & & view - > screen ( ) = = screen
& & ( ( allEdges | | edges . contains ( view - > location ( ) ) )
& & ( allModes | | ( view - > visibility ( ) & & modes . contains ( view - > visibility ( ) - > mode ( ) ) ) ) ) ) {
2017-12-24 21:54:45 +03:00
2018-01-14 18:30:29 +03:00
auto dockRect = view - > absGeometry ( ) ;
2017-02-10 02:11:34 +03:00
2018-01-14 18:30:29 +03:00
// Usually availableScreenRect is used by the desktop,
2018-08-30 08:47:53 +03:00
// but Latte don't have desktop, then here just
2018-01-14 18:30:29 +03:00
// need calculate available space for top and bottom location,
// because the left and right are those who dodge others docks
switch ( view - > location ( ) ) {
case Plasma : : Types : : TopEdge :
available . setTop ( dockRect . bottom ( ) + 1 ) ;
break ;
2017-02-12 02:59:09 +03:00
2018-01-14 18:30:29 +03:00
case Plasma : : Types : : BottomEdge :
available . setBottom ( dockRect . top ( ) - 1 ) ;
break ;
2017-12-24 21:54:45 +03:00
2018-01-14 18:30:29 +03:00
case Plasma : : Types : : LeftEdge :
available . setLeft ( dockRect . right ( ) + 1 ) ;
2017-12-24 21:54:45 +03:00
2018-01-14 18:30:29 +03:00
break ;
2017-12-24 21:54:45 +03:00
2018-01-14 18:30:29 +03:00
case Plasma : : Types : : RightEdge :
available . setRight ( dockRect . left ( ) - 1 ) ;
2017-12-24 21:54:45 +03:00
2018-01-14 18:30:29 +03:00
break ;
2017-10-21 10:21:40 +03:00
2018-01-14 18:30:29 +03:00
default :
//! bypass clang warnings
break ;
}
2017-02-10 02:11:34 +03:00
}
}
}
2017-02-11 06:12:17 +03:00
return available ;
2016-12-25 10:25:27 +03:00
}
2017-02-24 21:58:21 +03:00
void DockCorona : : addOutput ( QScreen * screen )
{
Q_ASSERT ( screen ) ;
2017-02-26 03:43:41 +03:00
2017-02-26 21:06:31 +03:00
int id = m_screenPool - > id ( screen - > name ( ) ) ;
2017-02-27 20:46:10 +03:00
if ( id = = - 1 ) {
2017-02-26 21:06:31 +03:00
int newId = m_screenPool - > firstAvailableId ( ) ;
m_screenPool - > insertScreenMapping ( newId , screen - > name ( ) ) ;
}
2018-11-23 17:57:33 +03:00
connect ( screen , & QScreen : : geometryChanged , this , [ = ] ( ) {
const int id = m_screenPool - > id ( screen - > name ( ) ) ;
if ( id > = 0 ) {
emit screenGeometryChanged ( id ) ;
emit availableScreenRegionChanged ( ) ;
emit availableScreenRectChanged ( ) ;
}
} ) ;
emit availableScreenRectChanged ( ) ;
emit screenAdded ( m_screenPool - > id ( screen - > name ( ) ) ) ;
2017-02-24 21:58:21 +03:00
}
void DockCorona : : primaryOutputChanged ( )
{
2018-04-01 15:17:12 +03:00
m_docksScreenSyncTimer . start ( ) ;
2017-02-24 21:58:21 +03:00
}
void DockCorona : : screenRemoved ( QScreen * screen )
{
Q_ASSERT ( screen ) ;
2017-02-26 03:43:41 +03:00
}
void DockCorona : : screenCountChanged ( )
{
2017-03-01 21:49:21 +03:00
m_docksScreenSyncTimer . start ( ) ;
2017-02-26 03:43:41 +03:00
}
2017-03-02 19:07:29 +03:00
//! the central functions that updates loading/unloading dockviews
//! concerning screen changed (for multi-screen setups mainly)
2018-01-07 14:50:27 +03:00
void DockCorona : : syncDockViewsToScreens ( )
2017-02-26 03:43:41 +03:00
{
2018-01-11 21:34:16 +03:00
m_layoutManager - > syncDockViewsToScreens ( ) ;
2017-02-24 21:58:21 +03:00
}
2016-12-31 00:25:27 +03:00
int DockCorona : : primaryScreenId ( ) const
2016-12-30 17:51:44 +03:00
{
2017-02-24 21:58:21 +03:00
return m_screenPool - > id ( qGuiApp - > primaryScreen ( ) - > name ( ) ) ;
2016-12-30 17:51:44 +03:00
}
2017-01-05 01:28:25 +03:00
void DockCorona : : closeApplication ( )
{
2018-03-26 20:31:17 +03:00
//! this code must be called asynchronously because it is called
//! also from qml (Settings window).
QTimer : : singleShot ( 5 , [ this ] ( ) {
m_layoutManager - > hideLatteSettingsDialog ( ) ;
m_layoutManager - > hideAllDocks ( ) ;
} ) ;
2018-02-24 11:54:35 +03:00
//! give the time for the docks to hide themselves
2018-03-26 20:31:17 +03:00
QTimer : : singleShot ( 500 , [ this ] ( ) {
2018-02-24 11:54:35 +03:00
qGuiApp - > quit ( ) ;
} ) ;
2017-01-05 01:28:25 +03:00
}
2017-01-29 08:16:28 +03:00
void DockCorona : : aboutApplication ( )
{
if ( aboutDialog ) {
aboutDialog - > hide ( ) ;
aboutDialog - > deleteLater ( ) ;
}
aboutDialog = new KAboutApplicationDialog ( KAboutData : : applicationData ( ) ) ;
connect ( aboutDialog . data ( ) , & QDialog : : finished , aboutDialog . data ( ) , & QObject : : deleteLater ) ;
2018-03-02 00:53:28 +03:00
m_wm - > skipTaskBar ( * aboutDialog ) ;
m_wm - > setKeepAbove ( * aboutDialog , true ) ;
2017-01-29 08:16:28 +03:00
aboutDialog - > show ( ) ;
}
2016-12-31 00:25:27 +03:00
int DockCorona : : screenForContainment ( const Plasma : : Containment * containment ) const
2016-12-25 10:25:27 +03:00
{
2017-02-12 16:58:39 +03:00
//FIXME: indexOf is not a proper way to support multi-screen
// as for environment to environment the indexes change
// also there is the following issue triggered
// from dockView adaptToScreen()
//
// in a multi-screen environment that
// primary screen is not set to 0 it was
// created an endless showing loop at
// startup (catch-up race) between
// screen:0 and primaryScreen
2017-02-24 21:58:21 +03:00
//case in which this containment is child of an applet, hello systray :)
2018-01-14 18:30:29 +03:00
2017-02-24 21:58:21 +03:00
if ( Plasma : : Applet * parentApplet = qobject_cast < Plasma : : Applet * > ( containment - > parent ( ) ) ) {
if ( Plasma : : Containment * cont = parentApplet - > containment ( ) ) {
return screenForContainment ( cont ) ;
} else {
return - 1 ;
}
}
2018-01-11 21:34:16 +03:00
QHash < const Plasma : : Containment * , DockView * > * views = m_layoutManager - > currentDockViews ( ) ;
2018-01-08 20:21:34 +03:00
2017-02-24 21:58:21 +03:00
//if the panel views already exist, base upon them
2018-01-11 21:34:16 +03:00
2018-01-14 18:30:29 +03:00
DockView * view = views ? views - > value ( containment ) : nullptr ;
2017-02-24 21:58:21 +03:00
if ( view & & view - > screen ( ) ) {
return m_screenPool - > id ( view - > screen ( ) - > name ( ) ) ;
}
//Failed? fallback on lastScreen()
//lastScreen() is the correct screen for panels
//It is also correct for desktops *that have the correct activity()*
//a containment with lastScreen() == 0 but another activity,
//won't be associated to a screen
2017-02-26 03:43:41 +03:00
// qDebug() << "ShellCorona screenForContainment: " << containment << " Last screen is " << containment->lastScreen();
2017-02-24 21:58:21 +03:00
for ( auto screen : qGuiApp - > screens ( ) ) {
// containment->lastScreen() == m_screenPool->id(screen->name()) to check if the lastScreen refers to a screen that exists/it's known
if ( containment - > lastScreen ( ) = = m_screenPool - > id ( screen - > name ( ) ) & &
2017-07-03 10:41:59 +03:00
( containment - > activity ( ) = = m_activityConsumer - > currentActivity ( ) | |
containment - > containmentType ( ) = = Plasma : : Types : : PanelContainment | | containment - > containmentType ( ) = = Plasma : : Types : : CustomPanelContainment ) ) {
2017-02-24 21:58:21 +03:00
return containment - > lastScreen ( ) ;
}
}
return - 1 ;
2016-12-25 10:25:27 +03:00
}
2017-02-15 07:54:41 +03:00
void DockCorona : : showAlternativesForApplet ( Plasma : : Applet * applet )
{
const QString alternativesQML = kPackage ( ) . filePath ( " appletalternativesui " ) ;
2017-02-24 21:58:21 +03:00
2017-02-15 07:54:41 +03:00
if ( alternativesQML . isEmpty ( ) ) {
return ;
}
2018-01-11 21:34:16 +03:00
QHash < const Plasma : : Containment * , DockView * > * views = m_layoutManager - > currentDockViews ( ) ;
2018-01-08 20:21:34 +03:00
2018-01-11 21:34:16 +03:00
DockView * dockView = ( * views ) [ applet - > containment ( ) ] ;
2017-08-09 04:52:42 +03:00
KDeclarative : : QmlObject * qmlObj { nullptr } ;
if ( dockView ) {
dockView - > setAlternativesIsShown ( true ) ;
qmlObj = new KDeclarative : : QmlObject ( dockView ) ;
} else {
qmlObj = new KDeclarative : : QmlObject ( this ) ;
}
2017-02-15 07:54:41 +03:00
qmlObj - > setInitializationDelayed ( true ) ;
qmlObj - > setSource ( QUrl : : fromLocalFile ( alternativesQML ) ) ;
AlternativesHelper * helper = new AlternativesHelper ( applet , qmlObj ) ;
qmlObj - > rootContext ( ) - > setContextProperty ( QStringLiteral ( " alternativesHelper " ) , helper ) ;
m_alternativesObjects < < qmlObj ;
qmlObj - > completeInitialization ( ) ;
2017-08-09 03:33:03 +03:00
2017-08-09 04:52:42 +03:00
//! Alternative dialog signals
2017-08-09 03:33:03 +03:00
connect ( helper , & QObject : : destroyed , this , [ dockView ] ( ) {
dockView - > setAlternativesIsShown ( false ) ;
} ) ;
2017-02-15 07:54:41 +03:00
connect ( qmlObj - > rootObject ( ) , SIGNAL ( visibleChanged ( bool ) ) ,
this , SLOT ( alternativesVisibilityChanged ( bool ) ) ) ;
2017-02-24 21:58:21 +03:00
connect ( applet , & Plasma : : Applet : : destroyedChanged , this , [ this , qmlObj ] ( bool destroyed ) {
2017-02-15 07:54:41 +03:00
if ( ! destroyed ) {
return ;
}
2017-02-24 21:58:21 +03:00
2017-02-15 07:54:41 +03:00
QMutableListIterator < KDeclarative : : QmlObject * > it ( m_alternativesObjects ) ;
2017-02-24 21:58:21 +03:00
2017-02-15 07:54:41 +03:00
while ( it . hasNext ( ) ) {
KDeclarative : : QmlObject * obj = it . next ( ) ;
2017-02-24 21:58:21 +03:00
2017-02-15 07:54:41 +03:00
if ( obj = = qmlObj ) {
it . remove ( ) ;
obj - > deleteLater ( ) ;
}
}
} ) ;
}
void DockCorona : : alternativesVisibilityChanged ( bool visible )
{
if ( visible ) {
return ;
}
QObject * root = sender ( ) ;
QMutableListIterator < KDeclarative : : QmlObject * > it ( m_alternativesObjects ) ;
2017-02-24 21:58:21 +03:00
2017-02-15 07:54:41 +03:00
while ( it . hasNext ( ) ) {
KDeclarative : : QmlObject * obj = it . next ( ) ;
2017-02-24 21:58:21 +03:00
2017-02-15 07:54:41 +03:00
if ( obj - > rootObject ( ) = = root ) {
it . remove ( ) ;
obj - > deleteLater ( ) ;
}
}
}
2016-12-31 00:25:27 +03:00
void DockCorona : : loadDefaultLayout ( )
2016-12-25 10:25:27 +03:00
{
qDebug ( ) < < " loading default layout " ;
//! Settting mutable for create a containment
setImmutability ( Plasma : : Types : : Mutable ) ;
QVariantList args ;
2016-12-25 16:58:14 +03:00
auto defaultContainment = createContainmentDelayed ( " org.kde.latte.containment " , args ) ;
2016-12-25 10:25:27 +03:00
defaultContainment - > setContainmentType ( Plasma : : Types : : PanelContainment ) ;
defaultContainment - > init ( ) ;
2017-01-16 22:07:49 +03:00
2016-12-25 10:25:27 +03:00
if ( ! defaultContainment | | ! defaultContainment - > kPackage ( ) . isValid ( ) ) {
qWarning ( ) < < " the requested containment plugin can not be located or loaded " ;
return ;
}
2017-01-16 22:07:49 +03:00
2016-12-25 10:25:27 +03:00
auto config = defaultContainment - > config ( ) ;
2016-12-28 16:17:36 +03:00
defaultContainment - > restore ( config ) ;
2018-01-31 21:38:22 +03:00
using Plasma : : Types ;
QList < Types : : Location > edges { Types : : BottomEdge , Types : : LeftEdge ,
Types : : TopEdge , Types : : RightEdge } ;
Layout * currentLayout = m_layoutManager - > activeLayout ( m_layoutManager - > currentLayoutName ( ) ) ;
if ( currentLayout ) {
edges = currentLayout - > freeEdges ( defaultContainment - > screen ( ) ) ;
}
2017-01-16 22:07:49 +03:00
2017-07-03 10:55:52 +03:00
if ( ( edges . count ( ) > 0 ) ) {
2016-12-29 21:50:47 +03:00
defaultContainment - > setLocation ( edges . at ( 0 ) ) ;
} else {
defaultContainment - > setLocation ( Plasma : : Types : : BottomEdge ) ;
2016-12-25 10:25:27 +03:00
}
2017-01-16 22:07:49 +03:00
2018-01-13 20:27:32 +03:00
if ( m_layoutManager - > memoryUsage ( ) = = Dock : : MultipleLayouts ) {
config . writeEntry ( " layoutId " , m_layoutManager - > currentLayoutName ( ) ) ;
}
2016-12-28 16:17:36 +03:00
defaultContainment - > updateConstraints ( Plasma : : Types : : StartupCompletedConstraint ) ;
2017-03-10 23:41:13 +03:00
2016-12-28 16:17:36 +03:00
defaultContainment - > save ( config ) ;
requestConfigSync ( ) ;
2017-03-10 23:41:13 +03:00
2016-12-28 16:17:36 +03:00
defaultContainment - > flushPendingConstraintsEvents ( ) ;
emit containmentAdded ( defaultContainment ) ;
emit containmentCreated ( defaultContainment ) ;
2017-03-10 23:41:13 +03:00
2018-01-13 20:27:32 +03:00
//m_layoutManager->addDock(defaultContainment);
2016-12-29 00:07:17 +03:00
defaultContainment - > createApplet ( QStringLiteral ( " org.kde.latte.plasmoid " ) ) ;
2016-12-25 10:25:27 +03:00
defaultContainment - > createApplet ( QStringLiteral ( " org.kde.plasma.analogclock " ) ) ;
}
2017-07-25 00:01:41 +03:00
QStringList DockCorona : : containmentsIds ( )
{
2018-01-14 18:30:29 +03:00
QStringList ids ;
2017-07-25 00:01:41 +03:00
2018-01-14 18:30:29 +03:00
foreach ( auto containment , containments ( ) ) {
ids < < QString : : number ( containment - > id ( ) ) ;
}
return ids ;
2017-07-25 00:01:41 +03:00
}
QStringList DockCorona : : appletsIds ( )
{
QStringList ids ;
2018-01-14 18:30:29 +03:00
foreach ( auto containment , containments ( ) ) {
2018-07-11 20:17:06 +03:00
auto applets = containment - > config ( ) . group ( " Applets " ) ;
ids < < applets . groupList ( ) ;
2017-07-25 00:01:41 +03:00
}
return ids ;
}
2017-03-11 11:06:10 +03:00
//! Activate launcher menu through dbus interface
void DockCorona : : activateLauncherMenu ( )
{
2017-06-04 01:58:03 +03:00
m_globalShortcuts - > activateLauncherMenu ( ) ;
2017-03-11 11:06:10 +03:00
}
2018-10-14 13:54:09 +03:00
void DockCorona : : windowColorScheme ( QString windowIdAndScheme )
{
int firstSlash = windowIdAndScheme . indexOf ( " - " ) ;
2018-10-26 23:36:40 +03:00
QString windowIdStr = windowIdAndScheme . mid ( 0 , firstSlash ) ;
QString schemeStr = windowIdAndScheme . mid ( firstSlash + 1 ) ;
2018-10-14 13:54:09 +03:00
m_wm - > setColorSchemeForWindow ( windowIdStr , schemeStr ) ;
}
2017-04-11 20:23:43 +03:00
//! update badge for specific dock item
void DockCorona : : updateDockItemBadge ( QString identifier , QString value )
{
2017-06-04 01:58:03 +03:00
m_globalShortcuts - > updateDockItemBadge ( identifier , value ) ;
2017-04-11 20:23:43 +03:00
}
2018-02-07 00:14:44 +03:00
void DockCorona : : switchToLayout ( QString layout )
{
m_layoutManager - > switchToLayout ( layout ) ;
}
void DockCorona : : showSettingsWindow ( int page )
{
Dock : : LatteConfigPage p = Dock : : LayoutPage ;
if ( page > = Dock : : LayoutPage & & page < = Dock : : PreferencesPage ) {
p = static_cast < Dock : : LatteConfigPage > ( page ) ;
}
m_layoutManager - > showLatteSettingsDialog ( p ) ;
}
2018-02-07 00:39:45 +03:00
QStringList DockCorona : : contextMenuData ( )
{
QStringList data ;
data < < QString : : number ( ( int ) m_layoutManager - > memoryUsage ( ) ) ;
data < < m_layoutManager - > currentLayoutName ( ) ;
foreach ( auto layoutName , m_layoutManager - > menuLayouts ( ) ) {
if ( m_layoutManager - > activeLayout ( layoutName ) ) {
data < < QString ( " 1, " + layoutName ) ;
} else {
data < < QString ( " 0, " + layoutName ) ;
}
}
return data ;
}
2016-12-31 00:25:27 +03:00
inline void DockCorona : : qmlRegisterTypes ( ) const
2016-12-25 10:25:27 +03:00
{
qmlRegisterType < QScreen > ( ) ;
}
2016-12-30 10:20:06 +03:00
}