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