1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 "nsUserIdleServiceGTK.h"
11 #include "nsDebug.h"
12 #include "prlink.h"
13 #include "mozilla/Logging.h"
14 #include "WidgetUtilsGtk.h"
15 
16 using mozilla::LogLevel;
17 
18 static mozilla::LazyLogModule sIdleLog("nsIUserIdleService");
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 (!mozilla::widget::GdkIsX11Display()) {
35     return;
36   }
37 
38   // This will leak - See comments in ~nsUserIdleServiceGTK().
39   PRLibrary* xsslib = PR_LoadLibrary("libXss.so.1");
40   if (!xsslib)  // ouch.
41   {
42     MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to find libXss.so!\n"));
43     return;
44   }
45 
46   _XSSQueryExtension = (_XScreenSaverQueryExtension_fn)PR_FindFunctionSymbol(
47       xsslib, "XScreenSaverQueryExtension");
48   _XSSAllocInfo = (_XScreenSaverAllocInfo_fn)PR_FindFunctionSymbol(
49       xsslib, "XScreenSaverAllocInfo");
50   _XSSQueryInfo = (_XScreenSaverQueryInfo_fn)PR_FindFunctionSymbol(
51       xsslib, "XScreenSaverQueryInfo");
52 
53   if (!_XSSQueryExtension)
54     MOZ_LOG(sIdleLog, LogLevel::Warning,
55             ("Failed to get XSSQueryExtension!\n"));
56   if (!_XSSAllocInfo)
57     MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to get XSSAllocInfo!\n"));
58   if (!_XSSQueryInfo)
59     MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to get XSSQueryInfo!\n"));
60 
61   sInitialized = true;
62 }
63 
nsUserIdleServiceGTK()64 nsUserIdleServiceGTK::nsUserIdleServiceGTK() : mXssInfo(nullptr) {
65   Initialize();
66 }
67 
~nsUserIdleServiceGTK()68 nsUserIdleServiceGTK::~nsUserIdleServiceGTK() {
69   if (mXssInfo) XFree(mXssInfo);
70 
71 // It is not safe to unload libXScrnSaver until each display is closed because
72 // the library registers callbacks through XESetCloseDisplay (Bug 397607).
73 // (Also the library and its functions are scoped for the file not the object.)
74 #if 0
75     if (xsslib) {
76         PR_UnloadLibrary(xsslib);
77         xsslib = nullptr;
78     }
79 #endif
80 }
81 
PollIdleTime(uint32_t * aIdleTime)82 bool nsUserIdleServiceGTK::PollIdleTime(uint32_t* aIdleTime) {
83   if (!sInitialized) {
84     // For some reason, we could not find xscreensaver.
85     return false;
86   }
87 
88   // Ask xscreensaver about idle time:
89   *aIdleTime = 0;
90 
91   // We might not have a display (cf. in xpcshell)
92   Display* dplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
93   if (!dplay) {
94     MOZ_LOG(sIdleLog, LogLevel::Warning, ("No display found!\n"));
95     return false;
96   }
97 
98   if (!_XSSQueryExtension || !_XSSAllocInfo || !_XSSQueryInfo) {
99     return false;
100   }
101 
102   int event_base, error_base;
103   if (_XSSQueryExtension(dplay, &event_base, &error_base)) {
104     if (!mXssInfo) mXssInfo = _XSSAllocInfo();
105     if (!mXssInfo) return false;
106     _XSSQueryInfo(dplay, GDK_ROOT_WINDOW(), mXssInfo);
107     *aIdleTime = mXssInfo->idle;
108     return true;
109   }
110   // If we get here, we couldn't get to XScreenSaver:
111   MOZ_LOG(sIdleLog, LogLevel::Warning, ("XSSQueryExtension returned false!\n"));
112   return false;
113 }
114 
UsePollMode()115 bool nsUserIdleServiceGTK::UsePollMode() { return sInitialized; }
116