Update DBus Notify method annotation name
[lxde/liblxqt.git] / lxqtscreensaver.cpp
CommitLineData
4ef6cee9 1/* BEGIN_COMMON_COPYRIGHT_HEADER
c4af778e 2 * (c)LGPL2+
4ef6cee9 3 *
b9223fe7 4 * LXQt - a lightweight, Qt based, desktop toolset
4ef6cee9 5 * http://razor-qt.org
6 *
7 * Copyright: 2010-2011 Razor team
8 * Authors:
9 * Petr Vanek <petr@scribus.info>
cd10d270
LP
10 * Copyright (c) 2016 Luís Pereira <luis.artur.pereira@gmail.com>
11 * Copyright (c) 2012 The Chromium Authors. All rights reserved.
4ef6cee9 12 *
13 * This program or library is free software; you can redistribute it
14 * and/or modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
c4af778e 16 * version 2.1 of the License, or (at your option) any later version.
4ef6cee9 17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22
23 * You should have received a copy of the GNU Lesser General
24 * Public License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301 USA
27 *
28 * END_COMMON_COPYRIGHT_HEADER */
29
e6389bfc 30#include <QProcess>
b6483430 31#include "lxqtscreensaver.h"
949dba2f 32#include "lxqttranslator.h"
4ef6cee9 33
cd10d270
LP
34#include <memory>
35
e6389bfc 36#include <XdgIcon>
afd3b116
JL
37#include <QMessageBox>
38#include <QAction>
fc185531
LP
39#include <QPointer>
40#include <QProcess>
41#include <QCoreApplication> // for Q_DECLARE_TR_FUNCTIONS
cd10d270
LP
42#include <QX11Info>
43
44#include <X11/extensions/scrnsaver.h>
45
46// Avoid polluting everything with X11/Xlib.h:
47typedef struct _XDisplay Display;
48
49typedef unsigned long XAtom;
50typedef unsigned long XID;
51
52extern "C" {
53int XFree(void*);
54}
55
56template <class T, class R, R (*F)(T*)>
57struct XObjectDeleter {
58 inline void operator()(void* ptr) const { F(static_cast<T*>(ptr)); }
59};
60
61template <class T, class D = XObjectDeleter<void, int, XFree>>
62using XScopedPtr = std::unique_ptr<T, D>;
63
afd3b116 64
fc185531 65namespace LXQt {
d9dcfbad 66
cd10d270
LP
67static bool GetProperty(XID window, const std::string& property_name, long max_length,
68 Atom* type, int* format, unsigned long* num_items,
69 unsigned char** property);
70
71
72static bool GetIntArrayProperty(XID window,
73 const std::string& property_name,
74 std::vector<int>* value);
75
76
77static bool GetProperty(XID window, const std::string& property_name, long max_length,
78 Atom* type, int* format, unsigned long* num_items,
79 unsigned char** property)
80{
81 Atom property_atom = XInternAtom(QX11Info::display(), property_name.c_str(), false);
82 unsigned long remaining_bytes = 0;
83 return XGetWindowProperty(QX11Info::display(),
84 window,
85 property_atom,
86 0, // offset into property data to read
87 max_length, // max length to get
88 False, // deleted
89 AnyPropertyType,
90 type,
91 format,
92 num_items,
93 &remaining_bytes,
94 property);
95}
96
97static bool GetIntArrayProperty(XID window,
98 const std::string& property_name,
99 std::vector<int>* value)
100{
101 Atom type = None;
102 int format = 0; // size in bits of each item in 'property'
103 unsigned long num_items = 0;
104 unsigned char* properties = NULL;
105
106 int result = GetProperty(window, property_name,
107 (~0L), // (all of them)
108 &type, &format, &num_items, &properties);
109 XScopedPtr<unsigned char> scoped_properties(properties);
110 if (result != Success)
111 return false;
112
113 if (format != 32)
114 return false;
115
116 long* int_properties = reinterpret_cast<long*>(properties);
117 value->clear();
118 for (unsigned long i = 0; i < num_items; ++i)
119 {
120 value->push_back(static_cast<int>(int_properties[i]));
121 }
122 return true;
123}
124
fc185531 125class ScreenSaverPrivate
4ef6cee9 126{
fc185531
LP
127 Q_DECLARE_TR_FUNCTIONS(LXQt::ScreenSaver);
128 Q_DECLARE_PUBLIC(ScreenSaver)
129 ScreenSaver* const q_ptr;
4ef6cee9 130
fc185531
LP
131public:
132 ScreenSaverPrivate(ScreenSaver *q) : q_ptr(q) {};
4ef6cee9 133
fc185531 134 void _l_xdgProcess_finished(int, QProcess::ExitStatus);
cd10d270
LP
135 bool isScreenSaverLocked();
136
fc185531
LP
137 QPointer<QProcess> m_xdgProcess;
138};
4ef6cee9 139
fc185531 140void ScreenSaverPrivate::_l_xdgProcess_finished(int err, QProcess::ExitStatus status)
4ef6cee9 141{
fe846f1b
PL
142 // http://portland.freedesktop.org/xdg-utils-1.1.0-rc1/scripts/xdg-screensaver
143
fc185531 144 Q_Q(ScreenSaver);
d036f7aa 145 if (err == 0)
fc185531 146 emit q->activated();
4ef6cee9 147 else
148 {
d036f7aa
PL
149 QMessageBox *box = new QMessageBox;
150 box->setAttribute(Qt::WA_DeleteOnClose);
151 box->setIcon(QMessageBox::Warning);
152
153 if (err == 1)
154 {
155 box->setWindowTitle(tr("Screen Saver Error"));
156 box->setText(tr("An error occurred starting screensaver. "
157 "Syntax error in xdg-screensaver arguments."));
158 }
159 else if (err == 3)
160 {
161 box->setWindowTitle(tr("Screen Saver Activation Error"));
162 box->setText(tr("An error occurred starting screensaver. "
163 "Ensure you have xscreensaver installed and running."));
164 }
165 else if (err == 4)
166 {
167 box->setWindowTitle(tr("Screen Saver Activation Error"));
168 box->setText(tr("An error occurred starting screensaver. "
169 "Action 'activate' failed. "
170 "Ensure you have xscreensaver installed and running."));
171 }
172 else
173 {
174 box->setWindowTitle(tr("Screen Saver Activation Error"));
175 box->setText(tr("An error occurred starting screensaver. "
176 "Unknown error - undocumented return value from xdg-screensaver: %1.")
177 .arg(err));
178 }
179
180 box->exec();
4ef6cee9 181 }
d036f7aa 182
fc185531
LP
183 emit q->done();
184}
185
cd10d270
LP
186bool ScreenSaverPrivate::isScreenSaverLocked()
187{
188 XScreenSaverInfo *info = 0;
189 Display *display = QX11Info::display();
190 XID window = DefaultRootWindow(display);
191 info = XScreenSaverAllocInfo();
192
193 XScreenSaverQueryInfo(QX11Info::display(), window, info);
194 const int state = info->state;
195 XFree(info);
196 if (state == ScreenSaverOn)
197 return true;
198
199 // Ironically, xscreensaver does not conform to the XScreenSaver protocol, so
200 // info.state == ScreenSaverOff or info.state == ScreenSaverDisabled does not
201 // necessarily mean that a screensaver is not active, so add a special check
202 // for xscreensaver.
203 XAtom lock_atom = XInternAtom(display, "LOCK", false);
204 std::vector<int> atom_properties;
205 if (GetIntArrayProperty(window, "_SCREENSAVER_STATUS", &atom_properties) &&
206 atom_properties.size() > 0)
207 {
208 if (atom_properties[0] == static_cast<int>(lock_atom))
209 return true;
210 }
211
212 return false;
213}
fc185531
LP
214
215ScreenSaver::ScreenSaver(QObject * parent)
216 : QObject(parent),
217 d_ptr(new ScreenSaverPrivate(this))
218{
219 Q_D(ScreenSaver);
220 d->m_xdgProcess = new QProcess(this);
221 connect(d->m_xdgProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
222 this, SLOT(_l_xdgProcess_finished(int,QProcess::ExitStatus)));
223}
224
225ScreenSaver::~ScreenSaver()
226{
227 delete d_ptr;
4ef6cee9 228}
229
fc185531
LP
230QList<QAction*> ScreenSaver::availableActions()
231{
232 QList<QAction*> ret;
233 QAction * act;
234
235 act = new QAction(XdgIcon::fromTheme("system-lock-screen", "lock"), tr("Lock Screen"), this);
236 connect(act, SIGNAL(triggered()), this, SLOT(lockScreen()));
237 ret.append(act);
238
239 return ret;
240}
241
242void ScreenSaver::lockScreen()
243{
244 Q_D(ScreenSaver);
cd10d270
LP
245 if (!d->isScreenSaverLocked())
246 d->m_xdgProcess->start("xdg-screensaver", QStringList() << "lock");
fc185531
LP
247}
248
249} // namespace LXQt
250
251#include "moc_lxqtscreensaver.cpp"