1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include <gtk/gtk.h>
9
10 #include "nsIdleServiceGTK.h"
11 #include "nsIServiceManager.h"
12 #include "nsDebug.h"
13 #include "prlink.h"
14 #include "mozilla/Logging.h"
15
16 using mozilla::LogLevel;
17
18 static mozilla::LazyLogModule sIdleLog("nsIIdleService");
19
20 typedef bool (*_XScreenSaverQueryExtension_fn)(Display* dpy, int* event_base,
21 int* error_base);
22
23 typedef XScreenSaverInfo* (*_XScreenSaverAllocInfo_fn)(void);
24
25 typedef void (*_XScreenSaverQueryInfo_fn)(Display* dpy, Drawable drw,
26 XScreenSaverInfo* info);
27
28 static bool sInitialized = false;
29 static _XScreenSaverQueryExtension_fn _XSSQueryExtension = nullptr;
30 static _XScreenSaverAllocInfo_fn _XSSAllocInfo = nullptr;
31 static _XScreenSaverQueryInfo_fn _XSSQueryInfo = nullptr;
32
Initialize()33 static void Initialize() {
34 if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) return;
35
36 // This will leak - See comments in ~nsIdleServiceGTK().
37 PRLibrary* xsslib = PR_LoadLibrary("libXss.so.1");
38 if (!xsslib) // ouch.
39 {
40 MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to find libXss.so!\n"));
41 return;
42 }
43
44 _XSSQueryExtension = (_XScreenSaverQueryExtension_fn)PR_FindFunctionSymbol(
45 xsslib, "XScreenSaverQueryExtension");
46 _XSSAllocInfo = (_XScreenSaverAllocInfo_fn)PR_FindFunctionSymbol(
47 xsslib, "XScreenSaverAllocInfo");
48 _XSSQueryInfo = (_XScreenSaverQueryInfo_fn)PR_FindFunctionSymbol(
49 xsslib, "XScreenSaverQueryInfo");
50
51 if (!_XSSQueryExtension)
52 MOZ_LOG(sIdleLog, LogLevel::Warning,
53 ("Failed to get XSSQueryExtension!\n"));
54 if (!_XSSAllocInfo)
55 MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to get XSSAllocInfo!\n"));
56 if (!_XSSQueryInfo)
57 MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to get XSSQueryInfo!\n"));
58
59 sInitialized = true;
60 }
61
nsIdleServiceGTK()62 nsIdleServiceGTK::nsIdleServiceGTK() : mXssInfo(nullptr) { Initialize(); }
63
~nsIdleServiceGTK()64 nsIdleServiceGTK::~nsIdleServiceGTK() {
65 if (mXssInfo) XFree(mXssInfo);
66
67 // It is not safe to unload libXScrnSaver until each display is closed because
68 // the library registers callbacks through XESetCloseDisplay (Bug 397607).
69 // (Also the library and its functions are scoped for the file not the object.)
70 #if 0
71 if (xsslib) {
72 PR_UnloadLibrary(xsslib);
73 xsslib = nullptr;
74 }
75 #endif
76 }
77
PollIdleTime(uint32_t * aIdleTime)78 bool nsIdleServiceGTK::PollIdleTime(uint32_t* aIdleTime) {
79 if (!sInitialized) {
80 // For some reason, we could not find xscreensaver.
81 return false;
82 }
83
84 // Ask xscreensaver about idle time:
85 *aIdleTime = 0;
86
87 // We might not have a display (cf. in xpcshell)
88 Display* dplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
89 if (!dplay) {
90 MOZ_LOG(sIdleLog, LogLevel::Warning, ("No display found!\n"));
91 return false;
92 }
93
94 if (!_XSSQueryExtension || !_XSSAllocInfo || !_XSSQueryInfo) {
95 return false;
96 }
97
98 int event_base, error_base;
99 if (_XSSQueryExtension(dplay, &event_base, &error_base)) {
100 if (!mXssInfo) mXssInfo = _XSSAllocInfo();
101 if (!mXssInfo) return false;
102 _XSSQueryInfo(dplay, GDK_ROOT_WINDOW(), mXssInfo);
103 *aIdleTime = mXssInfo->idle;
104 return true;
105 }
106 // If we get here, we couldn't get to XScreenSaver:
107 MOZ_LOG(sIdleLog, LogLevel::Warning, ("XSSQueryExtension returned false!\n"));
108 return false;
109 }
110
UsePollMode()111 bool nsIdleServiceGTK::UsePollMode() { return sInitialized; }
112