gecko-dev/widget/gtk/nsUserIdleServiceGTK.cpp
Florian Quèze d7356251cd Bug 1768920 - Avoid polling every 5 seconds in nsUserIdleService, r=dthayer,geckoview-reviewers,owlish.
This changes the behavior in a few ways:
- the 'active' notification is now only fired when a new user event has been received by Firefox, rather than by any application on the entire system.
- the 'active' notification will fire immediately when Firefox receives a new event. Before the patch is was fired within 5s of the user returning on some plateforms (eg. Mac) and immediately on some other platforms that already called ResetIdleTimeout (windows, gtk, android). I'm not sure if these existing calls to ResetIdleTimeout are really needed, nor if they add significant overhead.
- when an idle observer has been notified of 'idle', it won't be notified again until Firefox receives events. Before the patch, if the user used other applications while Firefox was in the background, we would keep sending active and idle notifications to our idle observers. This behavior was probably initially intended when the nsUserIdleService was introduced to support the use case of instant messaging clients, but doesn't seem to match the expectations of the existing consumers of the service.

Differential Revision: https://phabricator.services.mozilla.com/D166306
2023-01-16 19:53:33 +00:00

126 lines
3.7 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <gtk/gtk.h>
#include "nsUserIdleServiceGTK.h"
#include "nsDebug.h"
#include "prlink.h"
#include "mozilla/Logging.h"
#include "WidgetUtilsGtk.h"
using mozilla::LogLevel;
static mozilla::LazyLogModule sIdleLog("nsIUserIdleService");
#ifdef MOZ_X11
typedef bool (*_XScreenSaverQueryExtension_fn)(Display* dpy, int* event_base,
int* error_base);
typedef XScreenSaverInfo* (*_XScreenSaverAllocInfo_fn)(void);
typedef void (*_XScreenSaverQueryInfo_fn)(Display* dpy, Drawable drw,
XScreenSaverInfo* info);
static _XScreenSaverQueryExtension_fn _XSSQueryExtension = nullptr;
static _XScreenSaverAllocInfo_fn _XSSAllocInfo = nullptr;
static _XScreenSaverQueryInfo_fn _XSSQueryInfo = nullptr;
#endif
static bool sInitialized = false;
static void Initialize() {
#ifdef MOZ_X11
if (!mozilla::widget::GdkIsX11Display()) {
return;
}
// This will leak - See comments in ~nsUserIdleServiceGTK().
PRLibrary* xsslib = PR_LoadLibrary("libXss.so.1");
if (!xsslib) // ouch.
{
MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to find libXss.so!\n"));
return;
}
_XSSQueryExtension = (_XScreenSaverQueryExtension_fn)PR_FindFunctionSymbol(
xsslib, "XScreenSaverQueryExtension");
_XSSAllocInfo = (_XScreenSaverAllocInfo_fn)PR_FindFunctionSymbol(
xsslib, "XScreenSaverAllocInfo");
_XSSQueryInfo = (_XScreenSaverQueryInfo_fn)PR_FindFunctionSymbol(
xsslib, "XScreenSaverQueryInfo");
if (!_XSSQueryExtension)
MOZ_LOG(sIdleLog, LogLevel::Warning,
("Failed to get XSSQueryExtension!\n"));
if (!_XSSAllocInfo)
MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to get XSSAllocInfo!\n"));
if (!_XSSQueryInfo)
MOZ_LOG(sIdleLog, LogLevel::Warning, ("Failed to get XSSQueryInfo!\n"));
sInitialized = true;
#endif
}
#ifdef MOZ_X11
nsUserIdleServiceGTK::nsUserIdleServiceGTK() : mXssInfo(nullptr) {
#else
nsUserIdleServiceGTK::nsUserIdleServiceGTK() {
#endif
Initialize();
}
nsUserIdleServiceGTK::~nsUserIdleServiceGTK() {
#ifdef MOZ_X11
if (mXssInfo) XFree(mXssInfo);
#endif
// It is not safe to unload libXScrnSaver until each display is closed because
// the library registers callbacks through XESetCloseDisplay (Bug 397607).
// (Also the library and its functions are scoped for the file not the object.)
#if 0
if (xsslib) {
PR_UnloadLibrary(xsslib);
xsslib = nullptr;
}
#endif
}
bool nsUserIdleServiceGTK::PollIdleTime(uint32_t* aIdleTime) {
#ifdef MOZ_X11
if (!sInitialized) {
// For some reason, we could not find xscreensaver.
return false;
}
// Ask xscreensaver about idle time:
*aIdleTime = 0;
// We might not have a display (cf. in xpcshell)
Display* dplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
if (!dplay) {
MOZ_LOG(sIdleLog, LogLevel::Warning, ("No display found!\n"));
return false;
}
if (!_XSSQueryExtension || !_XSSAllocInfo || !_XSSQueryInfo) {
return false;
}
int event_base, error_base;
if (_XSSQueryExtension(dplay, &event_base, &error_base)) {
if (!mXssInfo) mXssInfo = _XSSAllocInfo();
if (!mXssInfo) return false;
_XSSQueryInfo(dplay, GDK_ROOT_WINDOW(), mXssInfo);
*aIdleTime = mXssInfo->idle;
return true;
}
// If we get here, we couldn't get to XScreenSaver:
MOZ_LOG(sIdleLog, LogLevel::Warning, ("XSSQueryExtension returned false!\n"));
#endif
return false;
}