Update DBus Notify method annotation name
[lxde/liblxqt.git] / lxqtscreensaver.cpp
1 /* BEGIN_COMMON_COPYRIGHT_HEADER
2 * (c)LGPL2+
3 *
4 * LXQt - a lightweight, Qt based, desktop toolset
5 * http://razor-qt.org
6 *
7 * Copyright: 2010-2011 Razor team
8 * Authors:
9 * Petr Vanek <petr@scribus.info>
10 * Copyright (c) 2016 Luís Pereira <luis.artur.pereira@gmail.com>
11 * Copyright (c) 2012 The Chromium Authors. All rights reserved.
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
16 * version 2.1 of the License, or (at your option) any later version.
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
30 #include <QProcess>
31 #include "lxqtscreensaver.h"
32 #include "lxqttranslator.h"
33
34 #include <memory>
35
36 #include <XdgIcon>
37 #include <QMessageBox>
38 #include <QAction>
39 #include <QPointer>
40 #include <QProcess>
41 #include <QCoreApplication> // for Q_DECLARE_TR_FUNCTIONS
42 #include <QX11Info>
43
44 #include <X11/extensions/scrnsaver.h>
45
46 // Avoid polluting everything with X11/Xlib.h:
47 typedef struct _XDisplay Display;
48
49 typedef unsigned long XAtom;
50 typedef unsigned long XID;
51
52 extern "C" {
53 int XFree(void*);
54 }
55
56 template <class T, class R, R (*F)(T*)>
57 struct XObjectDeleter {
58 inline void operator()(void* ptr) const { F(static_cast<T*>(ptr)); }
59 };
60
61 template <class T, class D = XObjectDeleter<void, int, XFree>>
62 using XScopedPtr = std::unique_ptr<T, D>;
63
64
65 namespace LXQt {
66
67 static 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
72 static bool GetIntArrayProperty(XID window,
73 const std::string& property_name,
74 std::vector<int>* value);
75
76
77 static 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
97 static 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
125 class ScreenSaverPrivate
126 {
127 Q_DECLARE_TR_FUNCTIONS(LXQt::ScreenSaver);
128 Q_DECLARE_PUBLIC(ScreenSaver)
129 ScreenSaver* const q_ptr;
130
131 public:
132 ScreenSaverPrivate(ScreenSaver *q) : q_ptr(q) {};
133
134 void _l_xdgProcess_finished(int, QProcess::ExitStatus);
135 bool isScreenSaverLocked();
136
137 QPointer<QProcess> m_xdgProcess;
138 };
139
140 void ScreenSaverPrivate::_l_xdgProcess_finished(int err, QProcess::ExitStatus status)
141 {
142 // http://portland.freedesktop.org/xdg-utils-1.1.0-rc1/scripts/xdg-screensaver
143
144 Q_Q(ScreenSaver);
145 if (err == 0)
146 emit q->activated();
147 else
148 {
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();
181 }
182
183 emit q->done();
184 }
185
186 bool 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 }
214
215 ScreenSaver::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
225 ScreenSaver::~ScreenSaver()
226 {
227 delete d_ptr;
228 }
229
230 QList<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
242 void ScreenSaver::lockScreen()
243 {
244 Q_D(ScreenSaver);
245 if (!d->isScreenSaverLocked())
246 d->m_xdgProcess->start("xdg-screensaver", QStringList() << "lock");
247 }
248
249 } // namespace LXQt
250
251 #include "moc_lxqtscreensaver.cpp"