1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
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/. */
10 #include "WakeLockListener.h"
11 #include "WidgetUtilsGtk.h"
12 #include "mozilla/ScopeExit.h"
14 #ifdef MOZ_ENABLE_DBUS
16 # include "AsyncDBus.h"
22 # include <gdk/gdkx.h>
23 # include "X11UndefineNone.h"
26 #if defined(MOZ_WAYLAND)
27 # include "mozilla/widget/nsWaylandDisplay.h"
28 # include "nsWindow.h"
31 #ifdef MOZ_ENABLE_DBUS
32 # define FREEDESKTOP_PORTAL_DESKTOP_TARGET "org.freedesktop.portal.Desktop"
33 # define FREEDESKTOP_PORTAL_DESKTOP_OBJECT "/org/freedesktop/portal/desktop"
34 # define FREEDESKTOP_PORTAL_DESKTOP_INTERFACE "org.freedesktop.portal.Inhibit"
35 # define FREEDESKTOP_PORTAL_DESKTOP_INHIBIT_IDLE_FLAG 8
37 # define FREEDESKTOP_SCREENSAVER_TARGET "org.freedesktop.ScreenSaver"
38 # define FREEDESKTOP_SCREENSAVER_OBJECT "/ScreenSaver"
39 # define FREEDESKTOP_SCREENSAVER_INTERFACE "org.freedesktop.ScreenSaver"
41 # define FREEDESKTOP_POWER_TARGET "org.freedesktop.PowerManagement"
42 # define FREEDESKTOP_POWER_OBJECT "/org/freedesktop/PowerManagement/Inhibit"
43 # define FREEDESKTOP_POWER_INTERFACE "org.freedesktop.PowerManagement.Inhibit"
45 # define SESSION_MANAGER_TARGET "org.gnome.SessionManager"
46 # define SESSION_MANAGER_OBJECT "/org/gnome/SessionManager"
47 # define SESSION_MANAGER_INTERFACE "org.gnome.SessionManager"
49 # define DBUS_TIMEOUT (-1)
52 using namespace mozilla
;
53 using namespace mozilla::widget
;
55 NS_IMPL_ISUPPORTS(WakeLockListener
, nsIDOMMozWakeLockListener
)
57 #define WAKE_LOCK_LOG(str, ...) \
58 MOZ_LOG(gLinuxWakeLockLog, mozilla::LogLevel::Debug, \
59 ("[%p] " str, this, ##__VA_ARGS__))
60 static mozilla::LazyLogModule
gLinuxWakeLockLog("LinuxWakeLock");
64 #if defined(MOZ_ENABLE_DBUS)
65 FreeDesktopScreensaver
= 1,
67 FreeDesktopPortal
= 3,
73 #if defined(MOZ_WAYLAND)
74 WaylandIdleInhibit
= 6,
79 #if defined(MOZ_ENABLE_DBUS)
80 bool IsDBusWakeLock(int aWakeLockType
) {
81 switch (aWakeLockType
) {
82 case FreeDesktopScreensaver
:
83 case FreeDesktopPower
:
85 case FreeDesktopPortal
:
94 const char* WakeLockTypeNames
[] = {
96 "FreeDesktopScreensaver",
101 "WaylandIdleInhibit",
106 class WakeLockTopic
{
108 NS_INLINE_DECL_REFCOUNTING(WakeLockTopic
)
110 explicit WakeLockTopic(const nsAString
& aTopic
) {
111 CopyUTF16toUTF8(aTopic
, mTopic
);
112 WAKE_LOCK_LOG("WakeLockTopic::WakeLockTopic() created %s", mTopic
.get());
113 if (sWakeLockType
== Initial
) {
114 SwitchToNextWakeLockType();
118 nsresult
InhibitScreensaver();
119 nsresult
UninhibitScreensaver();
125 bool SendUninhibit();
127 nsresult
ProcessNextRequest();
130 bool CheckXScreenSaverSupport();
131 bool InhibitXScreenSaver(bool inhibit
);
134 #if defined(MOZ_WAYLAND)
135 zwp_idle_inhibitor_v1
* mWaylandInhibitor
= nullptr;
136 static bool CheckWaylandIdleInhibitSupport();
137 bool InhibitWaylandIdle();
138 bool UninhibitWaylandIdle();
141 bool IsNativeWakeLock(int aWakeLockType
);
142 bool IsWakeLockTypeAvailable(int aWakeLockType
);
143 bool SwitchToNextWakeLockType();
145 #ifdef MOZ_ENABLE_DBUS
146 void DBusInhibitScreensaver(const char* aName
, const char* aPath
,
147 const char* aCall
, const char* aMethod
,
148 RefPtr
<GVariant
> aArgs
);
149 void DBusUninhibitScreensaver(const char* aName
, const char* aPath
,
150 const char* aCall
, const char* aMethod
);
152 void InhibitFreeDesktopPortal();
153 void InhibitFreeDesktopScreensaver();
154 void InhibitFreeDesktopPower();
157 void UninhibitFreeDesktopPortal();
158 void UninhibitFreeDesktopScreensaver();
159 void UninhibitFreeDesktopPower();
160 void UninhibitGNOME();
162 void DBusInhibitSucceeded(uint32_t aInhibitRequestID
);
163 void DBusInhibitFailed(bool aFatal
);
164 void DBusUninhibitSucceeded();
165 void DBusUninhibitFailed();
166 void ClearDBusInhibitToken();
168 ~WakeLockTopic() = default;
170 // Why is screensaver inhibited
178 } mState
= Uninhibited
;
181 const char* GetInhibitStateName(WakeLockState aState
) {
185 case WaitingToInhibit
:
186 return "waiting to inhibit";
188 return "uninhibited";
189 case WaitingToUninhibit
:
190 return "waiting to uninhibit";
196 #ifdef MOZ_ENABLE_DBUS
197 // mInhibitRequestID is received from success screen saver inhibit call
198 // and it's needed for screen saver enablement.
199 Maybe
<uint32_t> mInhibitRequestID
;
200 // Used to uninhibit org.freedesktop.portal.Inhibit request
201 nsCString mRequestObjectPath
;
202 // It's used to quit DBus operation on shutdown.
203 RefPtr
<GCancellable
> mCancellable
;
204 // If we fail to uninhibit DBus screensaver just disable
206 int mUninhibitAttempts
= 5;
209 std::queue
<WakeLockState
> mStateQueue
;
210 static int sWakeLockType
;
213 int WakeLockTopic::sWakeLockType
= Initial
;
215 #ifdef MOZ_ENABLE_DBUS
216 void WakeLockTopic::DBusInhibitSucceeded(uint32_t aInhibitRequestID
) {
218 mCancellable
= nullptr;
219 mInhibitRequestID
= Some(aInhibitRequestID
);
221 WAKE_LOCK_LOG("WakeLockTopic::DBusInhibitSucceeded(), mInhibitRequestID %u",
224 ProcessNextRequest();
227 void WakeLockTopic::DBusInhibitFailed(bool aFatal
) {
228 WAKE_LOCK_LOG("WakeLockTopic::DBusInhibitFailed(%d)", aFatal
);
230 mCancellable
= nullptr;
231 ClearDBusInhibitToken();
233 // Non-recoverable DBus error. Switch to another wake lock type.
234 if (aFatal
&& SwitchToNextWakeLockType()) {
235 mState
= WaitingToInhibit
;
240 // Flip back to uninhibited state as we failed.
241 mState
= Uninhibited
;
244 void WakeLockTopic::DBusUninhibitSucceeded() {
245 WAKE_LOCK_LOG("WakeLockTopic::DBusUninhibitSucceeded()");
246 mState
= Uninhibited
;
247 mCancellable
= nullptr;
248 ClearDBusInhibitToken();
249 ProcessNextRequest();
252 void WakeLockTopic::DBusUninhibitFailed() {
253 WAKE_LOCK_LOG("WakeLockTopic::DBusUninhibitFailed()");
255 mCancellable
= nullptr;
257 // We're in inhibited state and we can't switch back.
258 // Let's try again but there isn't much to do.
259 if (--mUninhibitAttempts
== 0) {
260 sWakeLockType
= Unsupported
;
264 void WakeLockTopic::ClearDBusInhibitToken() {
265 mRequestObjectPath
.Truncate();
266 mInhibitRequestID
= Nothing();
269 void WakeLockTopic::DBusInhibitScreensaver(const char* aName
, const char* aPath
,
272 RefPtr
<GVariant
> aArgs
) {
273 WAKE_LOCK_LOG("WakeLockTopic::DBusInhibitScreensaver()");
275 MOZ_DIAGNOSTIC_ASSERT(!mCancellable
);
276 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingToInhibit
);
278 mCancellable
= dont_AddRef(g_cancellable_new());
280 widget::CreateDBusProxyForBus(
282 GDBusProxyFlags(G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
|
283 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
),
284 /* aInterfaceInfo = */ nullptr, aName
, aPath
, aCall
, mCancellable
)
286 GetCurrentSerialEventTarget(), __func__
,
287 [self
= RefPtr
{this}, this, args
= RefPtr
{aArgs
},
288 aMethod
](RefPtr
<GDBusProxy
>&& aProxy
) {
290 "WakeLockTopic::DBusInhibitScreensaver() proxy created");
291 DBusProxyCall(aProxy
.get(), aMethod
, args
.get(),
292 G_DBUS_CALL_FLAGS_NONE
, DBUS_TIMEOUT
, mCancellable
)
294 GetCurrentSerialEventTarget(), __func__
,
295 [s
= RefPtr
{this}, this](RefPtr
<GVariant
>&& aResult
) {
296 if (!g_variant_is_of_type(aResult
.get(),
297 G_VARIANT_TYPE_TUPLE
) ||
298 g_variant_n_children(aResult
.get()) != 1) {
300 "WakeLockTopic::DBusInhibitScreensaver() wrong "
302 g_variant_get_type_string(aResult
.get()));
303 DBusInhibitFailed(/* aFatal */ true);
306 RefPtr
<GVariant
> variant
= dont_AddRef(
307 g_variant_get_child_value(aResult
.get(), 0));
308 if (!g_variant_is_of_type(variant
,
309 G_VARIANT_TYPE_UINT32
)) {
311 "WakeLockTopic::DBusInhibitScreensaver() wrong "
313 g_variant_get_type_string(aResult
.get()));
314 DBusInhibitFailed(/* aFatal */ true);
317 DBusInhibitSucceeded(g_variant_get_uint32(variant
));
319 [s
= RefPtr
{this}, this,
320 aMethod
](GUniquePtr
<GError
>&& aError
) {
321 // Failed to send inhibit request over proxy.
322 // Switch to another wake lock type.
324 "WakeLockTopic::DBusInhibitFailed() %s call failed : "
326 aMethod
, aError
->message
);
328 /* aFatal */ !IsCancelledGError(aError
.get()));
331 [self
= RefPtr
{this}, this](GUniquePtr
<GError
>&& aError
) {
332 // We failed to create DBus proxy. Switch to another
335 "WakeLockTopic::DBusInhibitScreensaver() Proxy creation "
338 DBusInhibitFailed(/* aFatal */ !IsCancelledGError(aError
.get()));
342 void WakeLockTopic::DBusUninhibitScreensaver(const char* aName
,
345 const char* aMethod
) {
346 WAKE_LOCK_LOG("WakeLockTopic::DBusUninhibitScreensaver() request id %d",
347 mInhibitRequestID
? *mInhibitRequestID
: -1);
349 if (!mInhibitRequestID
.isSome()) {
350 WAKE_LOCK_LOG(" missing inihibit token, quit.");
351 DBusUninhibitFailed();
355 MOZ_DIAGNOSTIC_ASSERT(!mCancellable
);
356 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingToUninhibit
);
358 mCancellable
= dont_AddRef(g_cancellable_new());
360 RefPtr
<GVariant
> variant
=
361 dont_AddRef(g_variant_ref_sink(g_variant_new("(u)", *mInhibitRequestID
)));
362 nsCOMPtr
<nsISerialEventTarget
> target
= GetCurrentSerialEventTarget();
363 widget::CreateDBusProxyForBus(
365 GDBusProxyFlags(G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
|
366 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
),
367 /* aInterfaceInfo = */ nullptr, aName
, aPath
, aCall
, mCancellable
)
370 [self
= RefPtr
{this}, this, args
= std::move(variant
), target
,
371 aMethod
](RefPtr
<GDBusProxy
>&& aProxy
) {
373 "WakeLockTopic::DBusUninhibitScreensaver() proxy created");
374 DBusProxyCall(aProxy
.get(), aMethod
, args
.get(),
375 G_DBUS_CALL_FLAGS_NONE
, DBUS_TIMEOUT
, mCancellable
)
378 [s
= RefPtr
{this}, this](RefPtr
<GVariant
>&& aResult
) {
379 DBusUninhibitSucceeded();
381 [s
= RefPtr
{this}, this,
382 aMethod
](GUniquePtr
<GError
>&& aError
) {
384 "WakeLockTopic::DBusUninhibitFailed() %s call failed "
386 aMethod
, aError
->message
);
387 DBusUninhibitFailed();
390 [self
= RefPtr
{this}, this](GUniquePtr
<GError
>&& aError
) {
392 "WakeLockTopic::DBusUninhibitFailed() Proxy creation failed: "
395 DBusUninhibitFailed();
399 void WakeLockTopic::InhibitFreeDesktopPortal() {
400 WAKE_LOCK_LOG("WakeLockTopic::InhibitFreeDesktopPortal()");
402 MOZ_DIAGNOSTIC_ASSERT(!mCancellable
);
403 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingToInhibit
);
405 mCancellable
= dont_AddRef(g_cancellable_new());
407 CreateDBusProxyForBus(
409 GDBusProxyFlags(G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
|
410 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
),
411 nullptr, FREEDESKTOP_PORTAL_DESKTOP_TARGET
,
412 FREEDESKTOP_PORTAL_DESKTOP_OBJECT
, FREEDESKTOP_PORTAL_DESKTOP_INTERFACE
,
415 GetCurrentSerialEventTarget(), __func__
,
416 [self
= RefPtr
{this}, this](RefPtr
<GDBusProxy
>&& aProxy
) {
418 g_variant_builder_init(&b
, G_VARIANT_TYPE_VARDICT
);
419 g_variant_builder_add(&b
, "{sv}", "reason",
420 g_variant_new_string(self
->mTopic
.get()));
423 // https://flatpak.github.io/xdg-desktop-portal/docs/#gdbus-org.freedesktop.portal.Inhibit
425 aProxy
.get(), "Inhibit",
426 g_variant_new("(sua{sv})", g_get_prgname(),
427 FREEDESKTOP_PORTAL_DESKTOP_INHIBIT_IDLE_FLAG
, &b
),
428 G_DBUS_CALL_FLAGS_NONE
, DBUS_TIMEOUT
, mCancellable
)
430 GetCurrentSerialEventTarget(), __func__
,
431 [s
= RefPtr
{this}, this](RefPtr
<GVariant
>&& aResult
) {
432 gchar
* requestObjectPath
= nullptr;
433 g_variant_get(aResult
, "(o)", &requestObjectPath
);
434 if (!requestObjectPath
) {
436 "WakeLockTopic::InhibitFreeDesktopPortal(): Unable "
437 "to get requestObjectPath\n");
438 DBusInhibitFailed(/* aFatal */ true);
442 "WakeLockTopic::InhibitFreeDesktopPortal(): "
443 "inhibited, objpath to unihibit: %s\n",
445 mRequestObjectPath
.Adopt(requestObjectPath
);
446 DBusInhibitSucceeded(0);
448 [s
= RefPtr
{this}, this](GUniquePtr
<GError
>&& aError
) {
450 /* aFatal */ !IsCancelledGError(aError
.get()));
452 "Failed to create DBus proxy for "
453 "org.freedesktop.portal.Desktop: %s\n",
457 [self
= RefPtr
{this}, this](GUniquePtr
<GError
>&& aError
) {
459 "Failed to create DBus proxy for "
460 "org.freedesktop.portal.Desktop: %s\n",
462 DBusInhibitFailed(/* aFatal */ !IsCancelledGError(aError
.get()));
466 void WakeLockTopic::InhibitFreeDesktopScreensaver() {
467 WAKE_LOCK_LOG("InhibitFreeDesktopScreensaver()");
468 DBusInhibitScreensaver(FREEDESKTOP_SCREENSAVER_TARGET
,
469 FREEDESKTOP_SCREENSAVER_OBJECT
,
470 FREEDESKTOP_SCREENSAVER_INTERFACE
, "Inhibit",
471 dont_AddRef(g_variant_ref_sink(g_variant_new(
472 "(ss)", g_get_prgname(), mTopic
.get()))));
475 void WakeLockTopic::InhibitFreeDesktopPower() {
476 WAKE_LOCK_LOG("InhibitFreeDesktopPower()");
477 DBusInhibitScreensaver(FREEDESKTOP_POWER_TARGET
, FREEDESKTOP_POWER_OBJECT
,
478 FREEDESKTOP_POWER_INTERFACE
, "Inhibit",
479 dont_AddRef(g_variant_ref_sink(g_variant_new(
480 "(ss)", g_get_prgname(), mTopic
.get()))));
483 void WakeLockTopic::InhibitGNOME() {
484 WAKE_LOCK_LOG("InhibitGNOME()");
485 static const uint32_t xid
= 0;
486 static const uint32_t flags
= (1 << 3); // Inhibit idle
487 DBusInhibitScreensaver(
488 SESSION_MANAGER_TARGET
, SESSION_MANAGER_OBJECT
, SESSION_MANAGER_INTERFACE
,
490 dont_AddRef(g_variant_ref_sink(
491 g_variant_new("(susu)", g_get_prgname(), xid
, mTopic
.get(), flags
))));
494 void WakeLockTopic::UninhibitFreeDesktopPortal() {
495 WAKE_LOCK_LOG("WakeLockTopic::UninhibitFreeDesktopPortal() object path: %s",
496 mRequestObjectPath
.get());
498 if (mRequestObjectPath
.IsEmpty()) {
499 WAKE_LOCK_LOG("UninhibitFreeDesktopPortal() failed: unknown object path\n");
500 DBusUninhibitFailed();
504 MOZ_DIAGNOSTIC_ASSERT(!mCancellable
);
505 MOZ_DIAGNOSTIC_ASSERT(mState
== WaitingToUninhibit
);
507 mCancellable
= dont_AddRef(g_cancellable_new());
509 nsCOMPtr
<nsISerialEventTarget
> target
= GetCurrentSerialEventTarget();
510 CreateDBusProxyForBus(
512 GDBusProxyFlags(G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
|
513 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
),
514 nullptr, FREEDESKTOP_PORTAL_DESKTOP_TARGET
, mRequestObjectPath
.get(),
515 "org.freedesktop.portal.Request", mCancellable
)
518 [self
= RefPtr
{this}, target
, this](RefPtr
<GDBusProxy
>&& aProxy
) {
519 DBusProxyCall(aProxy
.get(), "Close", nullptr,
520 G_DBUS_CALL_FLAGS_NONE
, DBUS_TIMEOUT
, mCancellable
)
523 [s
= RefPtr
{this}, this](RefPtr
<GVariant
>&& aResult
) {
524 DBusUninhibitSucceeded();
526 "WakeLockTopic::UninhibitFreeDesktopPortal() Inhibit "
529 [s
= RefPtr
{this}, this](GUniquePtr
<GError
>&& aError
) {
530 DBusUninhibitFailed();
532 "WakeLockTopic::UninhibitFreeDesktopPortal() "
533 "Removing inhibit failed: %s\n",
537 [self
= RefPtr
{this}, this](GUniquePtr
<GError
>&& aError
) {
539 "WakeLockTopic::UninhibitFreeDesktopPortal() Proxy creation "
542 DBusUninhibitFailed();
546 void WakeLockTopic::UninhibitFreeDesktopScreensaver() {
547 WAKE_LOCK_LOG("UninhibitFreeDesktopScreensaver()");
548 DBusUninhibitScreensaver(FREEDESKTOP_SCREENSAVER_TARGET
,
549 FREEDESKTOP_SCREENSAVER_OBJECT
,
550 FREEDESKTOP_SCREENSAVER_INTERFACE
, "UnInhibit");
553 void WakeLockTopic::UninhibitFreeDesktopPower() {
554 WAKE_LOCK_LOG("UninhibitFreeDesktopPower()");
555 DBusUninhibitScreensaver(FREEDESKTOP_POWER_TARGET
, FREEDESKTOP_POWER_OBJECT
,
556 FREEDESKTOP_POWER_INTERFACE
, "UnInhibit");
559 void WakeLockTopic::UninhibitGNOME() {
560 WAKE_LOCK_LOG("UninhibitGNOME()");
561 DBusUninhibitScreensaver(SESSION_MANAGER_TARGET
, SESSION_MANAGER_OBJECT
,
562 SESSION_MANAGER_INTERFACE
, "Uninhibit");
567 // TODO: Merge with Idle service?
568 typedef Bool (*_XScreenSaverQueryExtension_fn
)(Display
* dpy
, int* event_base
,
570 typedef Bool (*_XScreenSaverQueryVersion_fn
)(Display
* dpy
, int* major
,
572 typedef void (*_XScreenSaverSuspend_fn
)(Display
* dpy
, Bool suspend
);
574 static PRLibrary
* sXssLib
= nullptr;
575 static _XScreenSaverQueryExtension_fn _XSSQueryExtension
= nullptr;
576 static _XScreenSaverQueryVersion_fn _XSSQueryVersion
= nullptr;
577 static _XScreenSaverSuspend_fn _XSSSuspend
= nullptr;
580 bool WakeLockTopic::CheckXScreenSaverSupport() {
582 sXssLib
= PR_LoadLibrary("libXss.so.1");
588 _XSSQueryExtension
= (_XScreenSaverQueryExtension_fn
)PR_FindFunctionSymbol(
589 sXssLib
, "XScreenSaverQueryExtension");
590 _XSSQueryVersion
= (_XScreenSaverQueryVersion_fn
)PR_FindFunctionSymbol(
591 sXssLib
, "XScreenSaverQueryVersion");
592 _XSSSuspend
= (_XScreenSaverSuspend_fn
)PR_FindFunctionSymbol(
593 sXssLib
, "XScreenSaverSuspend");
594 if (!_XSSQueryExtension
|| !_XSSQueryVersion
|| !_XSSSuspend
) {
598 GdkDisplay
* gDisplay
= gdk_display_get_default();
599 if (!GdkIsX11Display(gDisplay
)) {
602 Display
* display
= GDK_DISPLAY_XDISPLAY(gDisplay
);
605 if (!_XSSQueryExtension(display
, &throwaway
, &throwaway
)) return false;
608 if (!_XSSQueryVersion(display
, &major
, &minor
)) return false;
609 // Needs to be compatible with version 1.1
610 if (major
!= 1) return false;
611 if (minor
< 1) return false;
613 WAKE_LOCK_LOG("XScreenSaver supported.");
618 bool WakeLockTopic::InhibitXScreenSaver(bool inhibit
) {
619 WAKE_LOCK_LOG("InhibitXScreenSaver %d", inhibit
);
621 // Set failed state now to remove WaitingTo* one
622 mState
= inhibit
? Uninhibited
: Inhibited
;
624 // Should only be called if CheckXScreenSaverSupport returns true.
625 // There's a couple of safety checks here nonetheless.
629 GdkDisplay
* gDisplay
= gdk_display_get_default();
630 if (!GdkIsX11Display(gDisplay
)) {
633 Display
* display
= GDK_DISPLAY_XDISPLAY(gDisplay
);
634 _XSSSuspend(display
, inhibit
);
636 WAKE_LOCK_LOG("InhibitXScreenSaver %d succeeded", inhibit
);
637 mState
= inhibit
? Inhibited
: Uninhibited
;
642 #if defined(MOZ_WAYLAND)
644 bool WakeLockTopic::CheckWaylandIdleInhibitSupport() {
645 nsWaylandDisplay
* waylandDisplay
= WaylandDisplayGet();
646 return waylandDisplay
&& waylandDisplay
->GetIdleInhibitManager() != nullptr;
649 bool WakeLockTopic::InhibitWaylandIdle() {
650 WAKE_LOCK_LOG("InhibitWaylandIdle()");
652 // Set failed state now to remove WaitingTo* one
653 mState
= Uninhibited
;
655 nsWaylandDisplay
* waylandDisplay
= WaylandDisplayGet();
656 if (!waylandDisplay
) {
660 nsWindow
* focusedWindow
= nsWindow::GetFocusedWindow();
661 if (!focusedWindow
) {
665 UninhibitWaylandIdle();
667 if (GdkWindow
* window
= focusedWindow
->GetGdkWindow()) {
668 wl_surface
* waylandSurface
= gdk_wayland_window_get_wl_surface(window
);
669 if (waylandSurface
) {
670 mWaylandInhibitor
= zwp_idle_inhibit_manager_v1_create_inhibitor(
671 waylandDisplay
->GetIdleInhibitManager(), waylandSurface
);
676 WAKE_LOCK_LOG("InhibitWaylandIdle() %s",
677 !!mWaylandInhibitor
? "succeeded" : "failed");
678 return !!mWaylandInhibitor
;
681 bool WakeLockTopic::UninhibitWaylandIdle() {
682 WAKE_LOCK_LOG("UninhibitWaylandIdle() mWaylandInhibitor %p",
685 mState
= Uninhibited
;
686 if (!mWaylandInhibitor
) {
689 zwp_idle_inhibitor_v1_destroy(mWaylandInhibitor
);
690 mWaylandInhibitor
= nullptr;
695 bool WakeLockTopic::SendInhibit() {
696 WAKE_LOCK_LOG("WakeLockTopic::SendInhibit() WakeLockType %s",
697 WakeLockTypeNames
[sWakeLockType
]);
698 MOZ_ASSERT(sWakeLockType
!= Initial
);
699 switch (sWakeLockType
) {
700 #if defined(MOZ_ENABLE_DBUS)
701 case FreeDesktopPortal
:
702 InhibitFreeDesktopPortal();
704 case FreeDesktopScreensaver
:
705 InhibitFreeDesktopScreensaver();
707 case FreeDesktopPower
:
708 InhibitFreeDesktopPower();
716 return InhibitXScreenSaver(true);
718 #if defined(MOZ_WAYLAND)
719 case WaylandIdleInhibit
:
720 return InhibitWaylandIdle();
728 bool WakeLockTopic::SendUninhibit() {
729 WAKE_LOCK_LOG("WakeLockTopic::SendUninhibit() WakeLockType %s",
730 WakeLockTypeNames
[sWakeLockType
]);
731 MOZ_ASSERT(sWakeLockType
!= Initial
);
732 switch (sWakeLockType
) {
733 #if defined(MOZ_ENABLE_DBUS)
734 case FreeDesktopPortal
:
735 UninhibitFreeDesktopPortal();
737 case FreeDesktopScreensaver
:
738 UninhibitFreeDesktopScreensaver();
740 case FreeDesktopPower
:
741 UninhibitFreeDesktopPower();
749 return InhibitXScreenSaver(false);
751 #if defined(MOZ_WAYLAND)
752 case WaylandIdleInhibit
:
753 return UninhibitWaylandIdle();
761 nsresult
WakeLockTopic::InhibitScreensaver() {
762 WAKE_LOCK_LOG("WakeLockTopic::InhibitScreensaver() state %s",
763 GetInhibitStateName(mState
));
764 // We're broken, don't even try
765 if (sWakeLockType
== Unsupported
) {
766 return NS_ERROR_FAILURE
;
768 mStateQueue
.push(Inhibited
);
769 if (mState
== WaitingToInhibit
|| mState
== WaitingToUninhibit
) {
772 return ProcessNextRequest();
775 nsresult
WakeLockTopic::UninhibitScreensaver() {
776 WAKE_LOCK_LOG("WakeLockTopic::UnInhibitScreensaver() state %s",
777 GetInhibitStateName(mState
));
778 // We're broken, don't even try
779 if (sWakeLockType
== Unsupported
) {
780 return NS_ERROR_FAILURE
;
782 mStateQueue
.push(Uninhibited
);
783 if (mState
== WaitingToInhibit
|| mState
== WaitingToUninhibit
) {
786 return ProcessNextRequest();
789 nsresult
WakeLockTopic::ProcessNextRequest() {
790 WAKE_LOCK_LOG("WakeLockTopic::ProcessNextRequest(): recent state %s",
791 GetInhibitStateName(mState
));
792 MOZ_DIAGNOSTIC_ASSERT(mState
== Inhibited
|| mState
== Uninhibited
);
794 while (!mStateQueue
.empty()) {
795 WakeLockState nextState
= mStateQueue
.front();
798 WAKE_LOCK_LOG("WakeLockTopic::ProcessNextRequest(): next state %s",
799 GetInhibitStateName(nextState
));
801 if (nextState
== mState
) {
807 mState
= WaitingToInhibit
;
808 return SendInhibit() ? NS_OK
: NS_ERROR_FAILURE
;
811 mState
= WaitingToUninhibit
;
812 return SendUninhibit() ? NS_OK
: NS_ERROR_FAILURE
;
814 MOZ_DIAGNOSTIC_CRASH("Wrong state!");
815 return NS_ERROR_FAILURE
;
819 WAKE_LOCK_LOG("WakeLockTopic::ProcessNextRequest(): empty queue");
823 void WakeLockTopic::Shutdown() {
824 WAKE_LOCK_LOG("WakeLockTopic::Shutdown() state %s",
825 GetInhibitStateName(mState
));
826 #if defined(MOZ_ENABLE_DBUS)
828 g_cancellable_cancel(mCancellable
);
829 mCancellable
= nullptr;
834 bool WakeLockTopic::IsWakeLockTypeAvailable(int aWakeLockType
) {
835 switch (aWakeLockType
) {
836 #if defined(MOZ_ENABLE_DBUS)
837 case FreeDesktopPortal
:
838 case FreeDesktopScreensaver
:
839 case FreeDesktopPower
:
845 if (!GdkIsX11Display()) {
848 if (!CheckXScreenSaverSupport()) {
849 WAKE_LOCK_LOG(" XScreenSaverSupport is missing!");
854 #if defined(MOZ_WAYLAND)
855 case WaylandIdleInhibit
:
856 if (!GdkIsWaylandDisplay()) {
859 if (!CheckWaylandIdleInhibitSupport()) {
860 WAKE_LOCK_LOG(" WaylandIdleInhibitSupport is missing!");
870 bool WakeLockTopic::IsNativeWakeLock(int aWakeLockType
) {
871 switch (aWakeLockType
) {
876 #if defined(MOZ_WAYLAND)
877 case WaylandIdleInhibit
:
885 bool WakeLockTopic::SwitchToNextWakeLockType() {
886 WAKE_LOCK_LOG("WakeLockTopic::SwitchToNextWakeLockType() WakeLockType %s",
887 WakeLockTypeNames
[sWakeLockType
]);
889 if (sWakeLockType
== Unsupported
) {
894 auto printWakeLocktype
= MakeScopeExit([&] {
895 WAKE_LOCK_LOG(" switched to WakeLockType %s",
896 WakeLockTypeNames
[sWakeLockType
]);
900 #if defined(MOZ_ENABLE_DBUS)
901 if (IsDBusWakeLock(sWakeLockType
)) {
902 mState
= Uninhibited
;
903 mCancellable
= nullptr;
904 ClearDBusInhibitToken();
908 while (sWakeLockType
!= Unsupported
) {
910 if (IsWakeLockTypeAvailable(sWakeLockType
)) {
917 WakeLockListener::WakeLockListener() = default;
919 WakeLockListener::~WakeLockListener() {
920 for (const auto& topic
: mTopics
.Values()) {
925 nsresult
WakeLockListener::Callback(const nsAString
& topic
,
926 const nsAString
& state
) {
927 if (!topic
.Equals(u
"screen"_ns
) && !topic
.Equals(u
"video-playing"_ns
) &&
928 !topic
.Equals(u
"autoscroll"_ns
)) {
932 RefPtr
<WakeLockTopic
> topicLock
= mTopics
.LookupOrInsertWith(
933 topic
, [&] { return MakeRefPtr
<WakeLockTopic
>(topic
); });
935 // Treat "locked-background" the same as "unlocked" on desktop linux.
936 bool shouldLock
= state
.EqualsLiteral("locked-foreground");
937 WAKE_LOCK_LOG("WakeLockListener topic %s state %s request lock %d",
938 NS_ConvertUTF16toUTF8(topic
).get(),
939 NS_ConvertUTF16toUTF8(state
).get(), shouldLock
);
941 return shouldLock
? topicLock
->InhibitScreensaver()
942 : topicLock
->UninhibitScreensaver();