зеркало из https://github.com/mozilla/gecko-dev.git
Bug 811261 - Implement WakeLockListener on Linux to disable screensaver while video is playing r=karl
This commit is contained in:
Родитель
591364d52b
Коммит
8fcc868a64
|
@ -11,3 +11,6 @@ CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
|
||||||
CFLAGS += $(TK_CFLAGS)
|
CFLAGS += $(TK_CFLAGS)
|
||||||
CXXFLAGS += $(TK_CFLAGS)
|
CXXFLAGS += $(TK_CFLAGS)
|
||||||
|
|
||||||
|
ifdef MOZ_ENABLE_DBUS
|
||||||
|
CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
|
||||||
|
endif
|
||||||
|
|
|
@ -0,0 +1,365 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||||
|
*/
|
||||||
|
/* 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 <dbus/dbus.h>
|
||||||
|
#include <dbus/dbus-glib-lowlevel.h>
|
||||||
|
|
||||||
|
#include "WakeLockListener.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
|
||||||
|
#define FREEDESKTOP_SCREENSAVER_TARGET "org.freedesktop.ScreenSaver"
|
||||||
|
#define FREEDESKTOP_SCREENSAVER_OBJECT "/ScreenSaver"
|
||||||
|
#define FREEDESKTOP_SCREENSAVER_INTERFACE "org.freedesktop.ScreenSaver"
|
||||||
|
|
||||||
|
#define SESSION_MANAGER_TARGET "org.gnome.SessionManager"
|
||||||
|
#define SESSION_MANAGER_OBJECT "/org/gnome/SessionManager"
|
||||||
|
#define SESSION_MANAGER_INTERFACE "org.gnome.SessionManager"
|
||||||
|
|
||||||
|
#define DBUS_TIMEOUT (-1)
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(WakeLockListener, nsIDOMMozWakeLockListener)
|
||||||
|
|
||||||
|
WakeLockListener* WakeLockListener::sSingleton = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
enum DesktopEnvironment {
|
||||||
|
FreeDesktop,
|
||||||
|
GNOME,
|
||||||
|
Unsupported,
|
||||||
|
};
|
||||||
|
|
||||||
|
class WakeLockTopic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WakeLockTopic(const nsAString& aTopic, DBusConnection* aConnection)
|
||||||
|
: mTopic(NS_ConvertUTF16toUTF8(aTopic))
|
||||||
|
, mConnection(aConnection)
|
||||||
|
, mDesktopEnvironment(FreeDesktop)
|
||||||
|
, mInhibitRequest(0)
|
||||||
|
, mShouldInhibit(false)
|
||||||
|
, mWaitingForReply(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult InhibitScreensaver(void);
|
||||||
|
nsresult UninhibitScreensaver(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool SendInhibit();
|
||||||
|
bool SendUninhibit();
|
||||||
|
|
||||||
|
bool SendFreeDesktopInhibitMessage();
|
||||||
|
bool SendGNOMEInhibitMessage();
|
||||||
|
bool SendMessage(DBusMessage* aMessage);
|
||||||
|
|
||||||
|
static void ReceiveInhibitReply(DBusPendingCall* aPending, void* aUserData);
|
||||||
|
void InhibitFailed();
|
||||||
|
void InhibitSucceeded(uint32_t aInhibitRequest);
|
||||||
|
|
||||||
|
nsAutoCString mTopic;
|
||||||
|
DBusConnection* mConnection;
|
||||||
|
|
||||||
|
DesktopEnvironment mDesktopEnvironment;
|
||||||
|
|
||||||
|
uint32_t mInhibitRequest;
|
||||||
|
|
||||||
|
bool mShouldInhibit;
|
||||||
|
bool mWaitingForReply;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
WakeLockTopic::SendMessage(DBusMessage* aMessage)
|
||||||
|
{
|
||||||
|
// send message and get a handle for a reply
|
||||||
|
DBusPendingCall* reply;
|
||||||
|
dbus_connection_send_with_reply(mConnection, aMessage, &reply,
|
||||||
|
DBUS_TIMEOUT);
|
||||||
|
dbus_message_unref(aMessage);
|
||||||
|
|
||||||
|
if (!reply) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_pending_call_set_notify(reply, &ReceiveInhibitReply, this, NULL);
|
||||||
|
dbus_pending_call_unref(reply);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WakeLockTopic::SendFreeDesktopInhibitMessage()
|
||||||
|
{
|
||||||
|
DBusMessage* message =
|
||||||
|
dbus_message_new_method_call(FREEDESKTOP_SCREENSAVER_TARGET,
|
||||||
|
FREEDESKTOP_SCREENSAVER_OBJECT,
|
||||||
|
FREEDESKTOP_SCREENSAVER_INTERFACE,
|
||||||
|
"Inhibit");
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* app = g_get_prgname();
|
||||||
|
const char* topic = mTopic.get();
|
||||||
|
dbus_message_append_args(message,
|
||||||
|
DBUS_TYPE_STRING, &app,
|
||||||
|
DBUS_TYPE_STRING, &topic,
|
||||||
|
DBUS_TYPE_INVALID);
|
||||||
|
|
||||||
|
return SendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WakeLockTopic::SendGNOMEInhibitMessage()
|
||||||
|
{
|
||||||
|
DBusMessage* message =
|
||||||
|
dbus_message_new_method_call(SESSION_MANAGER_TARGET,
|
||||||
|
SESSION_MANAGER_OBJECT,
|
||||||
|
SESSION_MANAGER_INTERFACE,
|
||||||
|
"Inhibit");
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t xid = 0;
|
||||||
|
static const uint32_t flags = (1 << 3); // Inhibit idle
|
||||||
|
const char* app = g_get_prgname();
|
||||||
|
const char* topic = mTopic.get();
|
||||||
|
dbus_message_append_args(message,
|
||||||
|
DBUS_TYPE_STRING, &app,
|
||||||
|
DBUS_TYPE_UINT32, &xid,
|
||||||
|
DBUS_TYPE_STRING, &topic,
|
||||||
|
DBUS_TYPE_UINT32, &flags,
|
||||||
|
DBUS_TYPE_INVALID);
|
||||||
|
|
||||||
|
return SendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
WakeLockTopic::SendInhibit()
|
||||||
|
{
|
||||||
|
bool sendOk = false;
|
||||||
|
|
||||||
|
switch (mDesktopEnvironment)
|
||||||
|
{
|
||||||
|
case FreeDesktop:
|
||||||
|
sendOk = SendFreeDesktopInhibitMessage();
|
||||||
|
break;
|
||||||
|
case GNOME:
|
||||||
|
sendOk = SendGNOMEInhibitMessage();
|
||||||
|
break;
|
||||||
|
case Unsupported:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendOk) {
|
||||||
|
mWaitingForReply = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WakeLockTopic::SendUninhibit()
|
||||||
|
{
|
||||||
|
DBusMessage* message = nullptr;
|
||||||
|
|
||||||
|
if (mDesktopEnvironment == FreeDesktop) {
|
||||||
|
message =
|
||||||
|
dbus_message_new_method_call(FREEDESKTOP_SCREENSAVER_TARGET,
|
||||||
|
FREEDESKTOP_SCREENSAVER_OBJECT,
|
||||||
|
FREEDESKTOP_SCREENSAVER_INTERFACE,
|
||||||
|
"UnInhibit");
|
||||||
|
} else if (mDesktopEnvironment == GNOME) {
|
||||||
|
message =
|
||||||
|
dbus_message_new_method_call(SESSION_MANAGER_TARGET,
|
||||||
|
SESSION_MANAGER_OBJECT,
|
||||||
|
SESSION_MANAGER_INTERFACE,
|
||||||
|
"Uninhibit");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_message_append_args(message,
|
||||||
|
DBUS_TYPE_UINT32, &mInhibitRequest,
|
||||||
|
DBUS_TYPE_INVALID);
|
||||||
|
|
||||||
|
dbus_connection_send(mConnection, message, nullptr);
|
||||||
|
dbus_connection_flush(mConnection);
|
||||||
|
dbus_message_unref(message);
|
||||||
|
|
||||||
|
mInhibitRequest = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
WakeLockTopic::InhibitScreensaver()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(!mShouldInhibit, "Screensaver is already inhibited");
|
||||||
|
mShouldInhibit = true;
|
||||||
|
|
||||||
|
if (mWaitingForReply) {
|
||||||
|
// We already have a screensaver inhibit request pending. This can happen
|
||||||
|
// if InhibitScreensaver is called, then UninhibitScreensaver, then
|
||||||
|
// InhibitScreensaver again quickly.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendInhibit() ? NS_OK : NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
WakeLockTopic::UninhibitScreensaver()
|
||||||
|
{
|
||||||
|
if (!mShouldInhibit) {
|
||||||
|
// Screensaver isn't inhibited. Nothing to do here.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mShouldInhibit = false;
|
||||||
|
|
||||||
|
if (mWaitingForReply) {
|
||||||
|
// If we're still waiting for a response to our inhibit request, we can't
|
||||||
|
// do anything until we get a dbus message back. The callbacks below will
|
||||||
|
// check |mShouldInhibit| and act accordingly.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendUninhibit() ? NS_OK : NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WakeLockTopic::InhibitFailed()
|
||||||
|
{
|
||||||
|
mWaitingForReply = false;
|
||||||
|
|
||||||
|
if (mDesktopEnvironment == FreeDesktop) {
|
||||||
|
mDesktopEnvironment = GNOME;
|
||||||
|
} else {
|
||||||
|
NS_ASSERTION(mDesktopEnvironment == GNOME, "Unknown desktop environment");
|
||||||
|
mDesktopEnvironment = Unsupported;
|
||||||
|
mShouldInhibit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mShouldInhibit) {
|
||||||
|
// We were interrupted by UninhibitScreensaver() before we could find the
|
||||||
|
// correct desktop environment.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendInhibit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WakeLockTopic::InhibitSucceeded(uint32_t aInhibitRequest)
|
||||||
|
{
|
||||||
|
mWaitingForReply = false;
|
||||||
|
mInhibitRequest = aInhibitRequest;
|
||||||
|
|
||||||
|
if (!mShouldInhibit) {
|
||||||
|
// We successfully inhibited the screensaver, but UninhibitScreensaver()
|
||||||
|
// was called while we were waiting for a reply.
|
||||||
|
SendUninhibit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
WakeLockTopic::ReceiveInhibitReply(DBusPendingCall* pending, void* user_data)
|
||||||
|
{
|
||||||
|
if (!WakeLockListener::GetSingleton(false)) {
|
||||||
|
// The WakeLockListener (and therefore our topic) was deleted while we were
|
||||||
|
// waiting for a reply.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WakeLockTopic* self = static_cast<WakeLockTopic*>(user_data);
|
||||||
|
|
||||||
|
DBusMessage* msg = dbus_pending_call_steal_reply(pending);
|
||||||
|
if (!msg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
|
||||||
|
uint32_t inhibitRequest;
|
||||||
|
|
||||||
|
if (dbus_message_get_args(msg, nullptr, DBUS_TYPE_UINT32,
|
||||||
|
&inhibitRequest, DBUS_TYPE_INVALID)) {
|
||||||
|
self->InhibitSucceeded(inhibitRequest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self->InhibitFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WakeLockListener::WakeLockListener()
|
||||||
|
: mConnection(dbus_bus_get(DBUS_BUS_SESSION, nullptr))
|
||||||
|
{
|
||||||
|
if (mConnection) {
|
||||||
|
dbus_connection_set_exit_on_disconnect(mConnection, false);
|
||||||
|
dbus_connection_setup_with_g_main(mConnection, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WakeLockListener::~WakeLockListener()
|
||||||
|
{
|
||||||
|
if (mConnection) {
|
||||||
|
dbus_connection_unref(mConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ WakeLockListener*
|
||||||
|
WakeLockListener::GetSingleton(bool aCreate)
|
||||||
|
{
|
||||||
|
if (!sSingleton && aCreate) {
|
||||||
|
sSingleton = new WakeLockListener();
|
||||||
|
sSingleton->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sSingleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
WakeLockListener::Shutdown()
|
||||||
|
{
|
||||||
|
sSingleton->Release();
|
||||||
|
sSingleton = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
WakeLockListener::Callback(const nsAString& topic, const nsAString& state)
|
||||||
|
{
|
||||||
|
if (!mConnection) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WakeLockTopic* topicLock = mTopics.Get(topic);
|
||||||
|
if (!topicLock) {
|
||||||
|
topicLock = new WakeLockTopic(topic, mConnection);
|
||||||
|
mTopics.Put(topic, topicLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat "locked-background" the same as "unlocked" on desktop linux.
|
||||||
|
bool shouldLock = state.EqualsLiteral("locked-foreground");
|
||||||
|
|
||||||
|
return shouldLock ?
|
||||||
|
topicLock->InhibitScreensaver() :
|
||||||
|
topicLock->UninhibitScreensaver();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||||
|
*/
|
||||||
|
/* 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 <unistd.h>
|
||||||
|
|
||||||
|
#ifndef __WakeLockListener_h__
|
||||||
|
#define __WakeLockListener_h__
|
||||||
|
|
||||||
|
#include "nsHashKeys.h"
|
||||||
|
#include "nsClassHashtable.h"
|
||||||
|
|
||||||
|
#include "nsIDOMWakeLockListener.h"
|
||||||
|
|
||||||
|
struct DBusConnection;
|
||||||
|
class WakeLockTopic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives WakeLock events and simply passes it on to the right WakeLockTopic
|
||||||
|
* to inhibit the screensaver.
|
||||||
|
*/
|
||||||
|
class WakeLockListener MOZ_FINAL : public nsIDOMMozWakeLockListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS;
|
||||||
|
|
||||||
|
static WakeLockListener* GetSingleton(bool aCreate = true);
|
||||||
|
static void Shutdown();
|
||||||
|
|
||||||
|
nsresult Callback(const nsAString& topic, const nsAString& state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
WakeLockListener();
|
||||||
|
~WakeLockListener();
|
||||||
|
|
||||||
|
static WakeLockListener* sSingleton;
|
||||||
|
|
||||||
|
DBusConnection* mConnection;
|
||||||
|
// Map of topic names to |WakeLockTopic|s.
|
||||||
|
// We assume a small, finite-sized set of topics.
|
||||||
|
nsClassHashtable<nsStringHashKey, WakeLockTopic> mTopics;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __WakeLockListener_h__
|
|
@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
|
||||||
'nsScreenManagerGtk.cpp',
|
'nsScreenManagerGtk.cpp',
|
||||||
'nsSound.cpp',
|
'nsSound.cpp',
|
||||||
'nsToolkit.cpp',
|
'nsToolkit.cpp',
|
||||||
|
'WakeLockListener.cpp',
|
||||||
'WidgetTraceEvent.cpp',
|
'WidgetTraceEvent.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
#include "mozilla/HangMonitor.h"
|
#include "mozilla/HangMonitor.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
|
#include "nsIPowerManagerService.h"
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
#include "WakeLockListener.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using mozilla::unused;
|
using mozilla::unused;
|
||||||
|
|
||||||
|
@ -82,6 +86,17 @@ nsAppShell::Init()
|
||||||
gWidgetDrawLog = PR_NewLogModule("WidgetDraw");
|
gWidgetDrawLog = PR_NewLogModule("WidgetDraw");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
nsCOMPtr<nsIPowerManagerService> powerManagerService =
|
||||||
|
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
|
||||||
|
|
||||||
|
if (powerManagerService) {
|
||||||
|
powerManagerService->AddWakeLockListener(WakeLockListener::GetSingleton());
|
||||||
|
} else {
|
||||||
|
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!sPollFunc) {
|
if (!sPollFunc) {
|
||||||
sPollFunc = g_main_context_get_poll_func(nullptr);
|
sPollFunc = g_main_context_get_poll_func(nullptr);
|
||||||
g_main_context_set_poll_func(nullptr, &PollWrapper);
|
g_main_context_set_poll_func(nullptr, &PollWrapper);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "nsBidiKeyboard.h"
|
#include "nsBidiKeyboard.h"
|
||||||
#include "nsScreenManagerGtk.h"
|
#include "nsScreenManagerGtk.h"
|
||||||
#include "nsGTKToolkit.h"
|
#include "nsGTKToolkit.h"
|
||||||
|
#include "WakeLockListener.h"
|
||||||
|
|
||||||
#ifdef NS_PRINTING
|
#ifdef NS_PRINTING
|
||||||
#include "nsPrintOptionsGTK.h"
|
#include "nsPrintOptionsGTK.h"
|
||||||
|
@ -280,6 +281,9 @@ nsWidgetGtk2ModuleDtor()
|
||||||
nsWindow::ReleaseGlobals();
|
nsWindow::ReleaseGlobals();
|
||||||
nsGTKToolkit::Shutdown();
|
nsGTKToolkit::Shutdown();
|
||||||
nsAppShellShutdown();
|
nsAppShellShutdown();
|
||||||
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
|
WakeLockListener::Shutdown();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static const mozilla::Module kWidgetModule = {
|
static const mozilla::Module kWidgetModule = {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче