1 /*
2     Copyright (C) 2016  P.L. Lucas <selairi@gmail.com>
3 
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Lesser General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) any later version.
8 
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Lesser General Public License for more details.
13 
14     You should have received a copy of the GNU Lesser General Public
15     License along with this library; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18 
19 #include "xrandrbrightness.h"
20 #include "brightnesswatcher.h"
21 
22 #include <QDebug>
23 #include <QTimer>
24 #include <LXQt/SingleApplication>
25 #include <QCommandLineParser>
26 #include <QMessageBox>
27 #include "brightnesssettings.h"
28 
29 #include <iostream>
30 
31 enum CommandLineParseResult {
32     CommandLineOk,
33     CommandLineError,
34     CommandLineVersionRequested,
35     CommandLineHelpRequested
36 };
37 
38 enum UiMode {
39     GUI,
40     TUI
41 };
42 
43 struct BrightnessConfigData {
44     BrightnessConfigData();
45 
46     UiMode mode;
47     bool increaseBrightness;
48     bool decreaseBrightness;
49     bool setBrightness;
50     float brightnessValue;
51     bool resetGamma;
52 };
53 
BrightnessConfigData()54 BrightnessConfigData::BrightnessConfigData()
55     : mode(UiMode::GUI),
56       increaseBrightness(false),
57       decreaseBrightness(false),
58       setBrightness(false),
59       brightnessValue(0.0f),
60       resetGamma(false)
61 {
62 }
63 
parseCommandLine(QCommandLineParser * parser,BrightnessConfigData * config,QString * errorMessage)64 static CommandLineParseResult parseCommandLine(QCommandLineParser *parser, BrightnessConfigData *config, QString *errorMessage)
65 {
66     parser->setApplicationDescription(QStringLiteral("LXQt Config Brightness"));
67     QCommandLineOption increaseOption(QStringList() << QStringLiteral("i") << QStringLiteral("increase"),
68             QObject::tr("Increase brightness."));
69     QCommandLineOption decreaseOption(QStringList() << QStringLiteral("d") << QStringLiteral("decrease"),
70             QObject::tr("Decrease brightness."));
71     QCommandLineOption setOption(QStringList() << QStringLiteral("s") << QStringLiteral("set"),
72             QObject::tr("Set brightness from 1 to 100."), QStringLiteral("brightness"));
73     QCommandLineOption resetGammaOption(QStringList() << QStringLiteral("r") << QStringLiteral("reset"),
74             QObject::tr("Reset gamma to default value."));
75     QCommandLineOption helpOption = parser->addHelpOption();
76     QCommandLineOption versionOption = parser->addVersionOption();
77     parser->addOption(increaseOption);
78     parser->addOption(decreaseOption);
79     parser->addOption(setOption);
80     parser->addOption(resetGammaOption);
81 
82     const QStringList args = QCoreApplication::arguments();
83     if (args.size() <= 1) { // no arguments given. GUI mode
84         config->mode = UiMode::GUI;
85         return CommandLineOk;
86     } else {
87         config->mode = UiMode::TUI;
88     }
89 
90     if (!parser->parse(QCoreApplication::arguments())) {
91         *errorMessage = parser->errorText();
92         return CommandLineError;
93     }
94 
95     if (parser->isSet(versionOption))
96         return CommandLineVersionRequested;
97 
98     if (parser->isSet(helpOption))
99         return CommandLineHelpRequested;
100 
101     const bool isIncreaseSet = parser->isSet(increaseOption);
102     const bool isDecreaseSet = parser->isSet(decreaseOption);
103 
104     const bool isSetBrightnessSet = parser->isSet(setOption);
105     float brightnessValue = 0.0f;
106     if (isSetBrightnessSet)
107         brightnessValue = parser->value(setOption).toFloat();
108 
109     const bool isResetGammaSet = parser->isSet(resetGammaOption);
110 
111     if ((isIncreaseSet || isDecreaseSet) && isSetBrightnessSet) {
112         *errorMessage = QObject::tr("%1: Can't use increase/decrease and set in conjunction").arg(QCoreApplication::applicationName());
113         return CommandLineError;
114     }
115 
116     if (isIncreaseSet && isDecreaseSet) {
117         *errorMessage = QObject::tr("%1: Can't use increase and decrease options in conjunction").arg(QCoreApplication::applicationName());
118         return CommandLineError;
119     }
120 
121     config->increaseBrightness = isIncreaseSet;
122     config->decreaseBrightness = isDecreaseSet;
123     config->setBrightness = isSetBrightnessSet;
124     config->brightnessValue = brightnessValue;
125     config->resetGamma = isResetGammaSet;
126 
127     return CommandLineOk;
128 }
129 
main(int argn,char * argv[])130 int main(int argn, char* argv[])
131 {
132     LXQt::SingleApplication app(argn, argv);
133     app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
134 
135     const QString VERINFO = QStringLiteral(LXQT_CONFIG_VERSION
136                                            "\nliblxqt   " LXQT_VERSION
137                                            "\nQt        " QT_VERSION_STR);
138     app.setApplicationVersion(VERINFO);
139 
140     // Command line options
141     QCommandLineParser parser;
142 
143     BrightnessConfigData config;
144     QString errorMessage;
145 
146     switch(parseCommandLine(&parser, &config, &errorMessage)) {
147     case CommandLineOk:
148         break;
149     case CommandLineError:
150         std::cerr << qPrintable(errorMessage);
151         std::cerr << "\n\n";
152         std::cerr << qPrintable(parser.helpText());
153         return EXIT_FAILURE;
154     case CommandLineVersionRequested:
155         parser.showVersion();
156         Q_UNREACHABLE();
157     case CommandLineHelpRequested:
158         parser.showHelp();
159         Q_UNREACHABLE();
160     }
161 
162     if (config.mode == UiMode::GUI) {
163         BrightnessSettings brightnessSettings;
164         brightnessSettings.setWindowIcon(QIcon(QLatin1String(ICON_DIR) + QStringLiteral("/brightnesssettings.svg")));
165         brightnessSettings.show();
166         return app.exec();
167     }
168 
169     // TUi mode
170     float sign = (config.decreaseBrightness) ? -1.0f : 1.0f;
171     float brightnessValue = qMin( qMax(config.brightnessValue, 0.0f), 100.0f ) / 100.0f;
172 
173     // Checks if backlight driver is available
174     LXQt::Backlight *mBacklight = new LXQt::Backlight(&app);
175     if (mBacklight->isBacklightAvailable() && !config.resetGamma) { // Use backlight driver
176         BrightnessWatcher *brightnessWatcher = new BrightnessWatcher(&app);
177 
178         // Qt::QueuedConnection needed. The event loop isn't running, yet.
179         QObject::connect(mBacklight, &LXQt::Backlight::backlightChanged,
180             brightnessWatcher, &BrightnessWatcher::changed, Qt::QueuedConnection);
181 
182         if (config.setBrightness)
183             sign = 0.0f;
184 
185         const int currentBacklight = mBacklight->getBacklight();
186         const int maxBacklight = mBacklight->getMaxBacklight();
187         int backlight = ( currentBacklight + sign*(maxBacklight/50 + 1) )*qAbs(sign) + brightnessValue*maxBacklight;
188 
189         mBacklight->setBacklight(backlight);
190 
191         // Timeout for situations where LXQtBacklight::setBacklight() doesn't
192         // produce a changed signal.
193         // QTimer::singleShot() doesn't allow to choose the type of connection.
194         // Qt::QueuedConnection needed. The event loop isn't running, yet.
195         QTimer *timeout = new QTimer(&app);
196         QObject::connect(timeout, &QTimer::timeout, &app, LXQt::SingleApplication::quit, Qt::QueuedConnection);
197         timeout->setSingleShot(true);
198         timeout->setInterval(2000);
199         timeout->start();
200     } else { // Use XRandr driver
201         XRandrBrightness *brightness = new XRandrBrightness();
202         const QList<MonitorInfo> monitors = brightness->getMonitorsInfo();
203         QList<MonitorInfo> monitorsChanged;
204         for(MonitorInfo monitor : monitors)
205         {
206             if(config.resetGamma)
207             {
208                 monitor.setBrightness(1.0f);
209                 monitorsChanged.append(monitor);
210                 continue;
211             }
212 
213             if(monitor.isBacklightSupported() )
214             {
215                 long backlight = ( monitor.backlight() + sign*(monitor.backlightMax()/50 + 1) )*qAbs(sign) + brightnessValue*monitor.backlightMax();
216                 if(backlight<monitor.backlightMax() && backlight>0)
217                 {
218                     monitor.setBacklight(backlight);
219                     monitorsChanged.append(monitor);
220                 }
221             }
222             else
223             {
224                 float brightness = (monitor.brightness() + 0.1f *sign)*qAbs(sign) + brightnessValue * 2.0f;
225                 if(brightness < 2.0f && brightness > 0.0f)
226                 {
227                     monitor.setBrightness(brightness);
228                     monitorsChanged.append(monitor);
229                 }
230             }
231         }
232         brightness->setMonitorsSettings(monitorsChanged);
233         delete brightness;
234         return 0;
235     }
236 
237     // We need to start the event loop. Otherwise the signal/slot mechanism
238     // won't work.
239     return app.exec();
240 }
241