// Copyright(c) 2017-2018 Alejandro Sirgo Rica & Contributors
//
// This file is part of Flameshot.
//
// Flameshot 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 3 of the License, or
// (at your option) any later version.
//
// Flameshot 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 Flameshot. If not, see .
#include "src/core/controller.h"
#include "singleapplication.h"
#include "src/utils/filenamehandler.h"
#include "src/utils/confighandler.h"
#include "src/cli/commandlineparser.h"
#include "src/utils/systemnotification.h"
#include "src/utils/pathinfo.h"
#include "src/core/capturerequest.h"
#include
#include
#include
#include
#include
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
#include "src/core/flameshotdbusadapter.h"
#include "src/utils/dbusutils.h"
#include
#include
#endif
int main(int argc, char *argv[]) {
// required for the button serialization
// TODO: change to QVector in v1.0
qRegisterMetaTypeStreamOperators >("QList");
qApp->setApplicationVersion(static_cast(APP_VERSION));
// no arguments, just launch Flameshot
if (argc == 1) {
SingleApplication app(argc, argv);
QTranslator translator;
QStringList trPaths = PathInfo::translationsPaths();
for (const QString &path: trPaths) {
bool match = translator.load(QLocale(),
"Internationalization", "_",
path);
if (match) {
break;
}
}
app.installTranslator(&translator);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
app.setApplicationName("flameshot");
app.setOrganizationName("Dharkael");
auto c = Controller::getInstance();
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
new FlameshotDBusAdapter(c);
QDBusConnection dbus = QDBusConnection::sessionBus();
if (!dbus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
dbus.registerObject("/", c);
dbus.registerService("org.dharkael.Flameshot");
#endif
// Exporting captures must be connected after the dbus interface
// or the dbus signal gets blocked until we end the exports.
c->enableExports();
return app.exec();
}
#ifndef Q_OS_WIN
/*--------------|
* CLI parsing |
* ------------*/
QCoreApplication app(argc, argv);
app.setApplicationName("flameshot");
app.setOrganizationName("Dharkael");
app.setApplicationVersion(qApp->applicationVersion());
CommandLineParser parser;
// Add description
parser.setDescription(
"Powerful yet simple to use screenshot software.");
parser.setGeneralErrorMessage("See 'flameshot --help'.");
// Arguments
CommandArgument fullArgument("full", "Capture the entire desktop.");
CommandArgument guiArgument("gui", "Start a manual capture in GUI mode.");
CommandArgument configArgument("config", "Configure flameshot.");
CommandArgument screenArgument("screen", "Capture a single screen.");
// Options
CommandOption pathOption(
{"p", "path"},
"Path where the capture will be saved",
"path");
CommandOption clipboardOption(
{"c", "clipboard"},
"Save the capture to the clipboard");
CommandOption delayOption(
{"d", "delay"},
"Delay time in milliseconds",
"milliseconds");
CommandOption filenameOption(
{"f", "filename"},
"Set the filename pattern",
"pattern");
CommandOption trayOption(
{"t", "trayicon"},
"Enable or disable the trayicon",
"bool");
CommandOption autostartOption(
{"a", "autostart"},
"Enable or disable run at startup",
"bool");
CommandOption showHelpOption(
{"s", "showhelp"},
"Show the help message in the capture mode",
"bool");
CommandOption mainColorOption(
{"m", "maincolor"},
"Define the main UI color",
"color-code");
CommandOption contrastColorOption(
{"k", "contrastcolor"},
"Define the contrast UI color",
"color-code");
CommandOption rawImageOption(
{"r", "raw"},
"Print raw PNG capture");
CommandOption screenNumberOption(
{"n", "number"},
"Define the screen to capture,\ndefault: screen containing the cursor",
"Screen number", "-1");
// Add checkers
auto colorChecker = [&parser](const QString &colorCode) -> bool {
QColor parsedColor(colorCode);
return parsedColor.isValid() && parsedColor.alphaF() == 1.0;
};
QString colorErr = "Invalid color, "
"this flag supports the following formats:\n"
"- #RGB (each of R, G, and B is a single hex digit)\n"
"- #RRGGBB\n- #RRRGGGBBB\n"
"- #RRRRGGGGBBBB\n"
"- Named colors like 'blue' or 'red'\n"
"You may need to escape the '#' sign as in '\\#FFF'";
const QString delayErr = "Invalid delay, it must be higher than 0";
const QString numberErr = "Invalid screen number, it must be non negative";
auto numericChecker = [&parser](const QString &delayValue) -> bool {
int value = delayValue.toInt();
return value >= 0;
};
const QString pathErr = "Invalid path, it must be a real path in the system";
auto pathChecker = [&parser, pathErr](const QString &pathValue) -> bool {
bool res = QDir(pathValue).exists();
if (!res) {
SystemNotification().sendMessage(QObject::tr(pathErr.toLatin1().data()));
}
return res;
};
const QString booleanErr = "Invalid value, it must be defined as 'true' or 'false'";
auto booleanChecker = [&parser](const QString &value) -> bool {
return value == "true" || value == "false";
};
contrastColorOption.addChecker(colorChecker, colorErr);
mainColorOption.addChecker(colorChecker, colorErr);
delayOption.addChecker(numericChecker, delayErr);
pathOption.addChecker(pathChecker, pathErr);
trayOption.addChecker(booleanChecker, booleanErr);
autostartOption.addChecker(booleanChecker, booleanErr);
showHelpOption.addChecker(booleanChecker, booleanErr);
screenNumberOption.addChecker(numericChecker, numberErr);
// Relationships
parser.AddArgument(guiArgument);
parser.AddArgument(screenArgument);
parser.AddArgument(fullArgument);
parser.AddArgument(configArgument);
auto helpOption = parser.addHelpOption();
auto versionOption = parser.addVersionOption();
parser.AddOptions({ pathOption, delayOption, rawImageOption }, guiArgument);
parser.AddOptions({ screenNumberOption, clipboardOption,pathOption,
delayOption, rawImageOption },
screenArgument);
parser.AddOptions({ pathOption, clipboardOption, delayOption, rawImageOption },
fullArgument);
parser.AddOptions({ autostartOption, filenameOption, trayOption,
showHelpOption, mainColorOption, contrastColorOption },
configArgument);
// Parse
if (!parser.parse(app.arguments())) {
goto finish;
}
// PROCESS DATA
//--------------
if (parser.isSet(helpOption) || parser.isSet(versionOption)) {
}
else if (parser.isSet(guiArgument)) { // GUI
QString pathValue = parser.value(pathOption);
int delay = parser.value(delayOption).toInt();
bool isRaw = parser.isSet(rawImageOption);
DBusUtils dbusUtils;
CaptureRequest req(CaptureRequest::GRAPHICAL_MODE, delay, pathValue);
uint id = req.id();
// Send message
QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot",
"/", "", "graphicCapture");
m << pathValue << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
QTimer t;
t.setInterval(delay + 1000 * 60 * 15); // 15 minutes timeout
QObject::connect(&t, &QTimer::timeout, qApp,
&QCoreApplication::quit);
t.start();
// wait
app.exec();
}
}
else if (parser.isSet(fullArgument)) { // FULL
QString pathValue = parser.value(pathOption);
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
// Not a valid command
if (!isRaw && !toClipboard && pathValue.isEmpty()) {
QTextStream out(stdout);
out << "Invalid format, set where to save the content with one of "
<< "the following flags:\n "
<< pathOption.dashedNames().join(", ") << "\n "
<< rawImageOption.dashedNames().join(", ") << "\n "
<< clipboardOption.dashedNames().join(", ") << "\n\n";
parser.parse(QStringList() << argv[0] << "full" << "-h");
goto finish;
}
CaptureRequest req(CaptureRequest::FULLSCREEN_MODE, delay, pathValue);
if (toClipboard) {
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
}
if (!pathValue.isEmpty()) {
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
}
uint id = req.id();
DBusUtils dbusUtils;
// Send message
QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot",
"/", "", "fullScreen");
m << pathValue << toClipboard << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(&t, &QTimer::timeout, qApp,
&QCoreApplication::quit);
t.start();
// wait
app.exec();
}
}
else if (parser.isSet(screenArgument)) { // SCREEN
QString numberStr = parser.value(screenNumberOption);
int number = numberStr.startsWith("-") ? -1 : numberStr.toInt();
QString pathValue = parser.value(pathOption);
int delay = parser.value(delayOption).toInt();
bool toClipboard = parser.isSet(clipboardOption);
bool isRaw = parser.isSet(rawImageOption);
// Not a valid command
if (!isRaw && !toClipboard && pathValue.isEmpty()) {
QTextStream out(stdout);
out << "Invalid format, set where to save the content with one of "
<< "the following flags:\n "
<< pathOption.dashedNames().join(", ") << "\n "
<< rawImageOption.dashedNames().join(", ") << "\n "
<< clipboardOption.dashedNames().join(", ") << "\n\n";
parser.parse(QStringList() << argv[0] << "screen" << "-h");
goto finish;
}
CaptureRequest req(CaptureRequest::SCREEN_MODE,
delay, pathValue, number);
if (toClipboard) {
req.addTask(CaptureRequest::CLIPBOARD_SAVE_TASK);
}
if (!pathValue.isEmpty()) {
req.addTask(CaptureRequest::FILESYSTEM_SAVE_TASK);
}
uint id = req.id();
DBusUtils dbusUtils;
// Send message
QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot",
"/", "", "captureScreen");
m << number << pathValue << toClipboard << delay << id;
QDBusConnection sessionBus = QDBusConnection::sessionBus();
dbusUtils.checkDBusConnection(sessionBus);
sessionBus.call(m);
if (isRaw) {
dbusUtils.connectPrintCapture(sessionBus, id);
// timeout just in case
QTimer t;
t.setInterval(delay + 2000);
QObject::connect(&t, &QTimer::timeout, qApp,
&QCoreApplication::quit);
t.start();
// wait
app.exec();
}
}
else if (parser.isSet(configArgument)) { // CONFIG
bool autostart = parser.isSet(autostartOption);
bool filename = parser.isSet(filenameOption);
bool tray = parser.isSet(trayOption);
bool help = parser.isSet(showHelpOption);
bool mainColor = parser.isSet(mainColorOption);
bool contrastColor = parser.isSet(contrastColorOption);
bool someFlagSet = (filename || tray || help ||
mainColor || contrastColor);
ConfigHandler config;
if (autostart) {
QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot",
"/", "", "autostartEnabled");
if (parser.value(autostartOption) == "false") {
m << false;
} else if (parser.value(autostartOption) == "true") {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
if (filename) {
QString newFilename(parser.value(filenameOption));
config.setFilenamePattern(newFilename);
FileNameHandler fh;
QTextStream(stdout)
<< QStringLiteral("The new pattern is '%1'\n"
"Parsed pattern example: %2\n").arg(newFilename)
.arg(fh.parsedPattern());
}
if (tray) {
QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot",
"/", "", "trayIconEnabled");
if (parser.value(trayOption) == "false") {
m << false;
} else if (parser.value(trayOption) == "true") {
m << true;
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
if (help) {
if (parser.value(showHelpOption) == "false") {
config.setShowHelp(false);
} else if (parser.value(showHelpOption) == "true") {
config.setShowHelp(true);
}
}
if (mainColor) {
QString colorCode = parser.value(mainColorOption);
QColor parsedColor(colorCode);
config.setUIMainColor(parsedColor);
}
if (contrastColor) {
QString colorCode = parser.value(contrastColorOption);
QColor parsedColor(colorCode);
config.setUIContrastColor(parsedColor);
}
// Open gui when no options
if (!someFlagSet) {
QDBusMessage m = QDBusMessage::createMethodCall("org.dharkael.Flameshot",
"/", "", "openConfig");
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected()) {
SystemNotification().sendMessage(
QObject::tr("Unable to connect via DBus"));
}
sessionBus.call(m);
}
}
finish:
#endif
return 0;
}