2017-01-02 17:05:30 -05:00
/*
* Copyright 2016 Smith AR < audoban @ openmailbox . org >
* 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-30 16:25:27 -05:00
# include "dockcorona.h"
2017-02-15 22:14:37 -05:00
# include "config-latte.h"
2017-07-22 23:15:54 +03:00
# include "importer.h"
2018-01-31 15:27:58 +02:00
# include "../liblattedock/dock.h"
2016-12-25 09:25:27 +02:00
# include <memory>
2017-02-26 12:37:46 -05:00
# include <csignal>
2016-12-25 09:25:27 +02:00
# include <QApplication>
2017-01-28 19:45:49 +02:00
# include <QDebug>
2016-12-25 09:25:27 +02:00
# include <QQuickWindow>
2016-12-30 16:25:27 -05:00
# include <QCommandLineParser>
# include <QCommandLineOption>
2016-12-25 09:25:27 +02:00
# include <QDebug>
2017-02-18 14:34:30 +02:00
# include <QDir>
# include <QLockFile>
2017-02-18 09:44:04 +02:00
# include <QSharedMemory>
2016-12-25 09:25:27 +02:00
2017-08-03 12:53:16 +03:00
# include <KCrash>
2016-12-25 09:25:27 +02:00
# include <KLocalizedString>
2017-01-29 00:16:28 -05:00
# include <KAboutData>
2017-03-11 10:06:10 +02:00
# include <KDBusService>
2017-05-26 15:36:50 +03:00
# include <KQuickAddons/QtQuickSettings>
2016-12-25 09:25:27 +02:00
2017-02-26 12:37:46 -05:00
2016-12-25 09:25:27 +02:00
//! COLORS
# define CNORMAL "\e[0m"
# define CIGREEN "\e[1;32m"
# define CGREEN "\e[0;32m"
# define CICYAN "\e[1;36m"
# define CCYAN "\e[0;36m"
# define CIRED "\e[1;31m"
# define CRED "\e[0;31m"
2017-01-29 00:16:28 -05:00
inline void configureAboutData ( ) ;
2018-04-02 14:37:19 +03:00
inline void detectPlatform ( int argc , char * * argv ) ;
2017-01-28 19:45:49 +02:00
2016-12-25 09:25:27 +02:00
int main ( int argc , char * * argv )
2017-03-11 10:06:10 +02:00
{
2018-03-07 18:11:40 +02:00
//Plasma scales itself to font DPI
//on X, where we don't have compositor scaling, this generally works fine.
//also there are bugs on older Qt, especially when it comes to fractional scaling
//there's advantages to disabling, and (other than small context menu icons) few advantages in enabling
//On wayland, it's different. Everything is simpler as all co-ordinates are in the same co-ordinate system
//we don't have fractional scaling on the client so don't hit most the remaining bugs and
//even if we don't use Qt scaling the compositor will try to scale us anyway so we have no choice
if ( ! qEnvironmentVariableIsSet ( " PLASMA_USE_QT_SCALING " ) ) {
qunsetenv ( " QT_DEVICE_PIXEL_RATIO " ) ;
QCoreApplication : : setAttribute ( Qt : : AA_DisableHighDpiScaling ) ;
} else {
QCoreApplication : : setAttribute ( Qt : : AA_UseHighDpiPixmaps ) ;
}
2017-02-17 21:14:31 +02:00
2016-12-25 09:25:27 +02:00
QQuickWindow : : setDefaultAlphaBuffer ( true ) ;
2018-04-02 14:37:19 +03:00
const bool qpaVariable = qEnvironmentVariableIsSet ( " QT_QPA_PLATFORM " ) ;
detectPlatform ( argc , argv ) ;
2016-12-25 09:25:27 +02:00
QApplication app ( argc , argv ) ;
2018-04-02 14:37:19 +03:00
if ( ! qpaVariable ) {
// don't leak the env variable to processes we start
qunsetenv ( " QT_QPA_PLATFORM " ) ;
}
2017-05-26 15:36:50 +03:00
KQuickAddons : : QtQuickSettings : : init ( ) ;
2017-01-21 18:27:51 -05:00
KLocalizedString : : setApplicationDomain ( " latte-dock " ) ;
2017-01-08 17:40:05 -05:00
app . setWindowIcon ( QIcon : : fromTheme ( QStringLiteral ( " latte-dock " ) ) ) ;
2017-05-26 15:07:06 +03:00
//protect from closing app when changing to "alternative session" and back
app . setQuitOnLastWindowClosed ( false ) ;
2017-02-26 12:37:46 -05:00
2017-01-29 00:16:28 -05:00
configureAboutData ( ) ;
2017-02-26 12:37:46 -05:00
QCommandLineParser parser ;
parser . addHelpOption ( ) ;
parser . addVersionOption ( ) ;
parser . addOptions ( {
2018-05-23 14:57:27 +03:00
{ { " r " , " replace " } , i18nc ( " command line " , " Replace the current Latte instance. " ) }
2017-03-11 10:06:10 +02:00
, { { " d " , " debug " } , i18nc ( " command line " , " Show the debugging messages on stdout. " ) }
2017-12-17 18:34:50 +02:00
, { " default-layout " , i18nc ( " command line " , " Import and load default layout on startup. " ) }
, { " available-layouts " , i18nc ( " command line " , " Print available layouts " ) }
, { " layout " , i18nc ( " command line " , " Load specific layout on startup. " ) , i18nc ( " command line: load " , " layout_name " ) }
2017-12-17 19:08:35 +02:00
, { " import-layout " , i18nc ( " command line " , " Import and load a layout. " ) , i18nc ( " command line: import " , " file_name " ) }
, { " import-full " , i18nc ( " command line " , " Import full configuration. " ) , i18nc ( " command line: import " , " file_name " ) }
2018-01-31 15:27:58 +02:00
, { " single " , i18nc ( " command line " , " Single layout memory mode. Only one layout is active at any case. " ) }
, { " multiple " , i18nc ( " command line " , " Multiple layouts memory mode. Multiple layouts can be active at any time based on Activities running. " ) }
2017-02-26 12:37:46 -05:00
} ) ;
2018-01-31 15:05:57 +02:00
//! START: Hidden options for Developer and Debugging usage
QCommandLineOption graphicsOption ( QStringList ( ) < < QStringLiteral ( " graphics " ) ) ;
graphicsOption . setDescription ( QStringLiteral ( " Draw boxes around of the applets. " ) ) ;
graphicsOption . setHidden ( true ) ;
parser . addOption ( graphicsOption ) ;
QCommandLineOption withWindowOption ( QStringList ( ) < < QStringLiteral ( " with-window " ) ) ;
withWindowOption . setDescription ( QStringLiteral ( " Open a window with much debug information " ) ) ;
withWindowOption . setHidden ( true ) ;
parser . addOption ( withWindowOption ) ;
QCommandLineOption maskOption ( QStringList ( ) < < QStringLiteral ( " mask " ) ) ;
maskOption . setDescription ( QStringLiteral ( " Show messages of debugging for the mask (Only useful to devs). " ) ) ;
maskOption . setHidden ( true ) ;
parser . addOption ( maskOption ) ;
QCommandLineOption timersOption ( QStringList ( ) < < QStringLiteral ( " timers " ) ) ;
timersOption . setDescription ( QStringLiteral ( " Show messages for debugging the timers (Only useful to devs). " ) ) ;
timersOption . setHidden ( true ) ;
parser . addOption ( timersOption ) ;
QCommandLineOption spacersOption ( QStringList ( ) < < QStringLiteral ( " spacers " ) ) ;
spacersOption . setDescription ( QStringLiteral ( " Show visual indicators for debugging spacers (Only useful to devs). " ) ) ;
spacersOption . setHidden ( true ) ;
parser . addOption ( spacersOption ) ;
2018-07-08 20:51:30 +03:00
QCommandLineOption overloadedIconsOption ( QStringList ( ) < < QStringLiteral ( " overloaded-icons " ) ) ;
overloadedIconsOption . setDescription ( QStringLiteral ( " Show visual indicators for debugging overloaded applets icons (Only useful to devs). " ) ) ;
overloadedIconsOption . setHidden ( true ) ;
parser . addOption ( overloadedIconsOption ) ;
2018-01-31 15:05:57 +02:00
//! END: Hidden options
2017-02-26 12:37:46 -05:00
parser . process ( app ) ;
2017-12-17 18:34:50 +02:00
if ( parser . isSet ( QStringLiteral ( " available-layouts " ) ) ) {
2017-12-17 18:13:26 +02:00
QStringList layouts = Latte : : Importer : : availableLayouts ( ) ;
if ( layouts . count ( ) > 0 ) {
qInfo ( ) < < i18n ( " Available layouts that can be used to start Latte: " ) ;
foreach ( auto layout , layouts ) {
qInfo ( ) < < " " < < layout ;
}
} else {
qInfo ( ) < < i18n ( " There are no available layouts, during startup Default will be used. " ) ;
}
qGuiApp - > exit ( ) ;
return 0 ;
}
2017-12-17 18:34:50 +02:00
bool defaultLayoutOnStartup = false ;
2018-01-31 15:27:58 +02:00
int memoryUsage = - 1 ;
2017-12-17 18:34:50 +02:00
QString layoutNameOnStartup = " " ;
if ( parser . isSet ( QStringLiteral ( " default-layout " ) ) ) {
defaultLayoutOnStartup = true ;
} else if ( parser . isSet ( QStringLiteral ( " layout " ) ) ) {
layoutNameOnStartup = parser . value ( QStringLiteral ( " layout " ) ) ;
if ( ! Latte : : Importer : : layoutExists ( layoutNameOnStartup ) ) {
2018-08-02 18:39:32 +03:00
qInfo ( ) < < i18nc ( " layout missing " , " This layout doesn't exist in the system. " ) ;
2017-12-17 18:34:50 +02:00
qGuiApp - > exit ( ) ;
return 0 ;
}
}
2017-12-25 21:07:07 +02:00
QString username = qgetenv ( " USER " ) ;
if ( username . isEmpty ( ) )
username = qgetenv ( " USERNAME " ) ;
QLockFile lockFile { QDir : : tempPath ( ) + " /latte-dock. " + username + " .lock " } ;
2017-02-26 12:37:46 -05:00
int timeout { 100 } ;
2017-05-26 15:07:06 +03:00
2017-12-17 19:08:35 +02:00
if ( parser . isSet ( QStringLiteral ( " replace " ) ) | | parser . isSet ( QStringLiteral ( " import-full " ) ) ) {
2017-05-26 15:07:06 +03:00
qint64 pid { - 1 } ;
2017-02-26 12:37:46 -05:00
if ( lockFile . getLockInfo ( & pid , nullptr , nullptr ) ) {
2017-03-20 12:20:37 -05:00
kill ( static_cast < pid_t > ( pid ) , SIGINT ) ;
2017-02-26 12:37:46 -05:00
timeout = 3000 ;
}
}
if ( ! lockFile . tryLock ( timeout ) ) {
qInfo ( ) < < i18n ( " An instance is already running!, use --replace to restart Latte " ) ;
qGuiApp - > exit ( ) ;
2017-12-17 18:15:04 +02:00
return 0 ;
2017-02-26 12:37:46 -05:00
}
2017-12-17 19:08:35 +02:00
if ( parser . isSet ( QStringLiteral ( " import-full " ) ) ) {
bool imported = Latte : : Importer : : importHelper ( parser . value ( QStringLiteral ( " import-full " ) ) ) ;
2017-03-20 12:20:37 -05:00
if ( ! imported ) {
qInfo ( ) < < i18n ( " The configuration cannot be imported " ) ;
2017-12-17 18:15:04 +02:00
qGuiApp - > exit ( ) ;
return 0 ;
2017-03-20 12:20:37 -05:00
}
}
2017-12-17 19:08:35 +02:00
if ( parser . isSet ( QStringLiteral ( " import-layout " ) ) ) {
QString importedLayout = Latte : : Importer : : importLayoutHelper ( parser . value ( QStringLiteral ( " import-layout " ) ) ) ;
if ( importedLayout . isEmpty ( ) ) {
qInfo ( ) < < i18n ( " The layout cannot be imported " ) ;
qGuiApp - > exit ( ) ;
return 0 ;
} else {
layoutNameOnStartup = importedLayout ;
}
}
2018-01-31 15:27:58 +02:00
if ( parser . isSet ( QStringLiteral ( " multiple " ) ) ) {
memoryUsage = ( int ) ( Latte : : Dock : : MultipleLayouts ) ;
} else if ( parser . isSet ( QStringLiteral ( " single " ) ) ) {
memoryUsage = ( int ) ( Latte : : Dock : : SingleLayout ) ;
}
2017-02-26 12:49:19 -05:00
if ( parser . isSet ( QStringLiteral ( " debug " ) ) | | parser . isSet ( QStringLiteral ( " mask " ) ) ) {
2017-03-11 10:06:10 +02:00
//! set pattern for debug messages
//! [%{type}] [%{function}:%{line}] - %{message} [%{backtrace}]
2017-02-01 21:19:50 +02:00
2017-02-26 12:37:46 -05:00
qSetMessagePattern ( QStringLiteral (
CIGREEN " [%{type} " CGREEN " %{time h:mm:ss.zz} " CIGREEN " ] " CNORMAL
2017-03-11 10:06:10 +02:00
# ifndef QT_NO_DEBUG
2017-02-26 12:37:46 -05:00
CIRED " [ " CCYAN " %{function} " CIRED " : " CCYAN " %{line} " CIRED " ] "
2017-03-11 10:06:10 +02:00
# endif
2017-02-26 12:37:46 -05:00
CICYAN " - " CNORMAL " %{message} "
CIRED " %{if-fatal} \n %{backtrace depth=8 separator= \" \n \" }%{endif} "
" %{if-critical} \n %{backtrace depth=8 separator= \" \n \" }%{endif} " CNORMAL ) ) ;
2017-02-01 21:19:50 +02:00
} else {
2017-03-11 10:06:10 +02:00
const auto noMessageOutput = [ ] ( QtMsgType , const QMessageLogContext & , const QString & ) { } ;
2017-02-26 12:37:46 -05:00
qInstallMessageHandler ( noMessageOutput ) ;
}
2017-02-01 21:19:50 +02:00
2017-02-26 12:37:46 -05:00
auto signal_handler = [ ] ( int ) {
qGuiApp - > exit ( ) ;
} ;
std : : signal ( SIGKILL , signal_handler ) ;
std : : signal ( SIGINT , signal_handler ) ;
2017-01-29 00:16:28 -05:00
2017-08-03 12:53:16 +03:00
KCrash : : setDrKonqiEnabled ( true ) ;
2018-01-15 15:02:58 +02:00
KCrash : : setFlags ( KCrash : : AutoRestart | KCrash : : AlwaysDirectly ) ;
2017-08-03 12:53:16 +03:00
2018-01-31 15:27:58 +02:00
Latte : : DockCorona corona ( defaultLayoutOnStartup , layoutNameOnStartup , memoryUsage ) ;
2017-03-11 10:06:10 +02:00
KDBusService service ( KDBusService : : Unique ) ;
2016-12-25 09:25:27 +02:00
return app . exec ( ) ;
}
2017-01-29 00:16:28 -05:00
inline void configureAboutData ( )
{
KAboutData about ( QStringLiteral ( " lattedock " )
, QStringLiteral ( " Latte Dock " )
2017-02-15 22:14:37 -05:00
, QStringLiteral ( VERSION )
2017-01-29 17:17:28 -05:00
, i18n ( " Latte is a dock based on plasma frameworks that provides an elegant and "
" intuitive experience for your tasks and plasmoids. It animates its contents "
2017-09-08 21:29:33 +03:00
" by using parabolic zoom effect and tries to be there only when it is needed. "
2017-01-29 17:17:28 -05:00
" \n \n \" Art in Coffee \" " )
2017-01-29 00:16:28 -05:00
, KAboutLicense : : GPL_V2
, QStringLiteral ( " \251 2016-2017 Michail Vourlakos, Smith AR " ) ) ;
2017-02-03 00:21:51 -05:00
about . setHomepage ( WEBSITE ) ;
2017-01-29 00:16:28 -05:00
about . setBugAddress ( BUG_ADDRESS ) ;
about . setProgramLogo ( QIcon : : fromTheme ( QStringLiteral ( " latte-dock " ) ) ) ;
about . setDesktopFileName ( QStringLiteral ( " latte-dock " ) ) ;
// Authors
about . addAuthor ( QStringLiteral ( " Michail Vourlakos " ) , QString ( ) , QStringLiteral ( " mvourlakos@gmail.com " ) ) ;
about . addAuthor ( QStringLiteral ( " Smith AR " ) , QString ( ) , QStringLiteral ( " audoban@openmailbox.org " ) ) ;
KAboutData : : setApplicationData ( about ) ;
}
2018-04-02 14:37:19 +03:00
//! used the version provided by PW:KWorkspace
inline void detectPlatform ( int argc , char * * argv )
{
if ( qEnvironmentVariableIsSet ( " QT_QPA_PLATFORM " ) ) {
return ;
}
for ( int i = 0 ; i < argc ; i + + ) {
if ( qstrcmp ( argv [ i ] , " -platform " ) = = 0 | |
qstrcmp ( argv [ i ] , " --platform " ) = = 0 | |
QByteArray ( argv [ i ] ) . startsWith ( " -platform= " ) | |
QByteArray ( argv [ i ] ) . startsWith ( " --platform= " ) ) {
return ;
}
}
const QByteArray sessionType = qgetenv ( " XDG_SESSION_TYPE " ) ;
if ( sessionType . isEmpty ( ) ) {
return ;
}
if ( qstrcmp ( sessionType , " wayland " ) = = 0 ) {
qputenv ( " QT_QPA_PLATFORM " , " wayland " ) ;
} else if ( qstrcmp ( sessionType , " x11 " ) = = 0 ) {
qputenv ( " QT_QPA_PLATFORM " , " xcb " ) ;
}
}