[Test] Added tests for CUtil::SplitParams
[xbmc.git] / xbmc / application / ApplicationPowerHandling.cpp
blob4354b9b626ef996e3583a8f270b84682bbca3d28
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "ApplicationPowerHandling.h"
11 #include "GUIUserMessages.h"
12 #include "ServiceBroker.h"
13 #include "addons/Addon.h"
14 #include "addons/AddonManager.h"
15 #include "addons/addoninfo/AddonType.h"
16 #include "addons/gui/GUIDialogAddonSettings.h"
17 #include "application/ApplicationComponents.h"
18 #include "application/ApplicationPlayer.h"
19 #include "guilib/GUIComponent.h"
20 #include "guilib/GUIMessage.h"
21 #include "guilib/GUIWindowManager.h"
22 #include "input/actions/Action.h"
23 #include "input/actions/ActionIDs.h"
24 #include "interfaces/AnnouncementManager.h"
25 #include "interfaces/generic/ScriptInvocationManager.h"
26 #include "messaging/ApplicationMessenger.h"
27 #include "music/MusicLibraryQueue.h"
28 #include "powermanagement/DPMSSupport.h"
29 #include "powermanagement/PowerTypes.h"
30 #include "profiles/ProfileManager.h"
31 #include "pvr/PVRManager.h"
32 #include "pvr/guilib/PVRGUIActionsChannels.h"
33 #include "pvr/guilib/PVRGUIActionsPowerManagement.h"
34 #include "settings/Settings.h"
35 #include "settings/SettingsComponent.h"
36 #include "utils/AlarmClock.h"
37 #include "utils/log.h"
38 #include "video/VideoLibraryQueue.h"
39 #include "windowing/WinSystem.h"
41 void CApplicationPowerHandling::ResetScreenSaver()
43 // reset our timers
44 m_shutdownTimer.StartZero();
46 // screen saver timer is reset only if we're not already in screensaver or
47 // DPMS mode
48 if ((!m_screensaverActive && m_iScreenSaveLock == 0) && !m_dpmsIsActive)
49 ResetScreenSaverTimer();
52 void CApplicationPowerHandling::ResetScreenSaverTimer()
54 m_screenSaverTimer.StartZero();
57 void CApplicationPowerHandling::ResetSystemIdleTimer()
59 // reset system idle timer
60 m_idleTimer.StartZero();
63 void CApplicationPowerHandling::ResetNavigationTimer()
65 m_navigationTimer.StartZero();
68 void CApplicationPowerHandling::SetRenderGUI(bool renderGUI)
70 if (renderGUI && !m_renderGUI)
72 CGUIComponent* gui = CServiceBroker::GetGUI();
73 if (gui)
74 CServiceBroker::GetGUI()->GetWindowManager().MarkDirty();
76 m_renderGUI = renderGUI;
79 void CApplicationPowerHandling::StopScreenSaverTimer()
81 m_screenSaverTimer.Stop();
84 bool CApplicationPowerHandling::ToggleDPMS(bool manual)
86 auto winSystem = CServiceBroker::GetWinSystem();
87 if (!winSystem)
88 return false;
90 std::shared_ptr<CDPMSSupport> dpms = winSystem->GetDPMSManager();
91 if (!dpms)
92 return false;
94 if (manual || (m_dpmsIsManual == manual))
96 if (m_dpmsIsActive)
98 m_dpmsIsActive = false;
99 m_dpmsIsManual = false;
100 SetRenderGUI(true);
101 CheckOSScreenSaverInhibitionSetting();
102 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::GUI, "OnDPMSDeactivated");
103 return dpms->DisablePowerSaving();
105 else
107 if (dpms->EnablePowerSaving(dpms->GetSupportedModes()[0]))
109 m_dpmsIsActive = true;
110 m_dpmsIsManual = manual;
111 SetRenderGUI(false);
112 CheckOSScreenSaverInhibitionSetting();
113 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::GUI, "OnDPMSActivated");
114 return true;
118 return false;
121 bool CApplicationPowerHandling::WakeUpScreenSaverAndDPMS(bool bPowerOffKeyPressed /* = false */)
123 bool result = false;
125 // First reset DPMS, if active
126 if (m_dpmsIsActive)
128 if (m_dpmsIsManual)
129 return false;
130 //! @todo if screensaver lock is specified but screensaver is not active
131 //! (DPMS came first), activate screensaver now.
132 ToggleDPMS(false);
133 ResetScreenSaverTimer();
134 result = !m_screensaverActive || WakeUpScreenSaver(bPowerOffKeyPressed);
136 else if (m_screensaverActive)
137 result = WakeUpScreenSaver(bPowerOffKeyPressed);
139 if (result)
141 // allow listeners to ignore the deactivation if it precedes a powerdown/suspend etc
142 CVariant data(CVariant::VariantTypeObject);
143 data["shuttingdown"] = bPowerOffKeyPressed;
144 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::GUI,
145 "OnScreensaverDeactivated", data);
148 return result;
151 bool CApplicationPowerHandling::WakeUpScreenSaver(bool bPowerOffKeyPressed /* = false */)
153 if (m_iScreenSaveLock == 2)
154 return false;
156 // if Screen saver is active
157 if (m_screensaverActive && !m_screensaverIdInUse.empty())
159 if (m_iScreenSaveLock == 0)
161 const std::shared_ptr<CProfileManager> profileManager =
162 CServiceBroker::GetSettingsComponent()->GetProfileManager();
163 if (profileManager->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE &&
164 (profileManager->UsingLoginScreen() ||
165 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
166 CSettings::SETTING_MASTERLOCK_STARTUPLOCK)) &&
167 profileManager->GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE &&
168 m_screensaverIdInUse != "screensaver.xbmc.builtin.dim" &&
169 m_screensaverIdInUse != "screensaver.xbmc.builtin.black" &&
170 m_screensaverIdInUse != "visualization")
172 m_iScreenSaveLock = 2;
173 CGUIMessage msg(GUI_MSG_CHECK_LOCK, 0, 0);
175 CGUIWindow* pWindow =
176 CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_SCREENSAVER);
177 if (pWindow)
178 pWindow->OnMessage(msg);
181 if (m_iScreenSaveLock == -1)
183 m_iScreenSaveLock = 0;
184 return true;
187 // disable screensaver
188 m_screensaverActive = false;
189 m_iScreenSaveLock = 0;
190 ResetScreenSaverTimer();
192 if (m_screensaverIdInUse == "visualization")
194 // we can just continue as usual from vis mode
195 return false;
197 else if (m_screensaverIdInUse == "screensaver.xbmc.builtin.dim" ||
198 m_screensaverIdInUse == "screensaver.xbmc.builtin.black" ||
199 m_screensaverIdInUse.empty())
201 return true;
203 else
204 { // we're in screensaver window
205 if (m_pythonScreenSaver)
207 // What sound does a python screensaver make?
208 #define SCRIPT_ALARM "sssssscreensaver"
209 #define SCRIPT_TIMEOUT 15 // seconds
211 /* FIXME: This is a hack but a proper fix is non-trivial. Basically this code
212 * makes sure the addon gets terminated after we've moved out of the screensaver window.
213 * If we don't do this, we may simply lockup.
215 g_alarmClock.Start(SCRIPT_ALARM, SCRIPT_TIMEOUT,
216 "StopScript(" + m_pythonScreenSaver->LibPath() + ")", true, false);
217 m_pythonScreenSaver.reset();
219 if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_SCREENSAVER)
220 CServiceBroker::GetGUI()->GetWindowManager().PreviousWindow(); // show the previous window
221 else if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_SLIDESHOW)
222 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_ACTION, WINDOW_SLIDESHOW, -1,
223 static_cast<void*>(new CAction(ACTION_STOP)));
225 return true;
227 else
228 return false;
231 void CApplicationPowerHandling::CheckOSScreenSaverInhibitionSetting()
233 // Kodi screen saver overrides OS one: always inhibit OS screen saver then
234 // except when DPMS is active (inhibiting the screen saver then might also
235 // disable DPMS again)
236 if (!m_dpmsIsActive &&
237 !CServiceBroker::GetSettingsComponent()
238 ->GetSettings()
239 ->GetString(CSettings::SETTING_SCREENSAVER_MODE)
240 .empty() &&
241 CServiceBroker::GetWinSystem()->GetOSScreenSaver())
243 if (!m_globalScreensaverInhibitor)
245 m_globalScreensaverInhibitor =
246 CServiceBroker::GetWinSystem()->GetOSScreenSaver()->CreateInhibitor();
249 else if (m_globalScreensaverInhibitor)
251 m_globalScreensaverInhibitor.Release();
255 void CApplicationPowerHandling::CheckScreenSaverAndDPMS()
257 bool maybeScreensaver = true;
258 if (m_dpmsIsActive)
259 maybeScreensaver = false;
260 else if (m_screensaverActive)
261 maybeScreensaver = false;
262 else if (CServiceBroker::GetSettingsComponent()
263 ->GetSettings()
264 ->GetString(CSettings::SETTING_SCREENSAVER_MODE)
265 .empty())
266 maybeScreensaver = false;
268 auto winSystem = CServiceBroker::GetWinSystem();
269 if (!winSystem)
270 return;
272 std::shared_ptr<CDPMSSupport> dpms = winSystem->GetDPMSManager();
274 bool maybeDPMS = true;
275 if (m_dpmsIsActive)
276 maybeDPMS = false;
277 else if (!dpms || !dpms->IsSupported())
278 maybeDPMS = false;
279 else if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
280 CSettings::SETTING_POWERMANAGEMENT_DISPLAYSOFF) <= 0)
281 maybeDPMS = false;
283 // whether the current state of the application should be regarded as active even when there is no
284 // explicit user activity such as input
285 bool haveIdleActivity = false;
287 if (m_bResetScreenSaver)
289 m_bResetScreenSaver = false;
290 haveIdleActivity = true;
293 // When inhibit screensaver is enabled prevent screensaver from kicking in
294 if (m_bInhibitScreenSaver)
295 haveIdleActivity = true;
297 // Are we playing a video and it is not paused?
298 const auto& components = CServiceBroker::GetAppComponents();
299 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
300 if (appPlayer && appPlayer->IsPlayingVideo() && !appPlayer->IsPaused())
301 haveIdleActivity = true;
303 // Are we playing audio and screensaver is disabled globally for audio?
304 else if (appPlayer && appPlayer->IsPlayingAudio() &&
305 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
306 CSettings::SETTING_SCREENSAVER_DISABLEFORAUDIO))
308 haveIdleActivity = true;
311 // Handle OS screen saver state
312 if (haveIdleActivity && CServiceBroker::GetWinSystem()->GetOSScreenSaver())
314 // Always inhibit OS screen saver during these kinds of activities
315 if (!m_screensaverInhibitor)
317 m_screensaverInhibitor =
318 CServiceBroker::GetWinSystem()->GetOSScreenSaver()->CreateInhibitor();
321 else if (m_screensaverInhibitor)
323 m_screensaverInhibitor.Release();
326 // Has the screen saver window become active?
327 if (maybeScreensaver &&
328 CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_SCREENSAVER))
330 m_screensaverActive = true;
331 maybeScreensaver = false;
334 if (m_screensaverActive && haveIdleActivity)
336 WakeUpScreenSaverAndDPMS();
337 return;
340 if (!maybeScreensaver && !maybeDPMS)
341 return; // Nothing to do.
343 // See if we need to reset timer.
344 if (haveIdleActivity)
346 ResetScreenSaverTimer();
347 return;
350 float elapsed = m_screenSaverTimer.IsRunning() ? m_screenSaverTimer.GetElapsedSeconds() : 0.f;
352 // DPMS has priority (it makes the screensaver not needed)
353 if (maybeDPMS && elapsed > CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
354 CSettings::SETTING_POWERMANAGEMENT_DISPLAYSOFF) *
357 ToggleDPMS(false);
358 WakeUpScreenSaver();
360 else if (maybeScreensaver &&
361 elapsed > CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
362 CSettings::SETTING_SCREENSAVER_TIME) *
365 ActivateScreenSaver();
369 // activate the screensaver.
370 // if forceType is true, we ignore the various conditions that can alter
371 // the type of screensaver displayed
372 void CApplicationPowerHandling::ActivateScreenSaver(bool forceType /*= false */)
374 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
375 const auto& components = CServiceBroker::GetAppComponents();
376 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
378 m_screensaverActive = true;
379 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::GUI, "OnScreensaverActivated");
381 // disable screensaver lock from the login screen
382 m_iScreenSaveLock =
383 CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_LOGIN_SCREEN ? 1 : 0;
385 m_screensaverIdInUse = settings->GetString(CSettings::SETTING_SCREENSAVER_MODE);
387 if (!forceType)
389 if (m_screensaverIdInUse == "screensaver.xbmc.builtin.dim" ||
390 m_screensaverIdInUse == "screensaver.xbmc.builtin.black" || m_screensaverIdInUse.empty())
392 return;
395 // Enforce Dim for special cases.
396 bool bUseDim = false;
397 if (appPlayer && appPlayer->IsPlayingVideo() &&
398 settings->GetBool(CSettings::SETTING_SCREENSAVER_USEDIMONPAUSE))
399 bUseDim = true;
400 else if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().IsRunningChannelScan())
401 bUseDim = true;
403 if (bUseDim)
404 m_screensaverIdInUse = "screensaver.xbmc.builtin.dim";
407 if (m_screensaverIdInUse == "screensaver.xbmc.builtin.dim" ||
408 m_screensaverIdInUse == "screensaver.xbmc.builtin.black" || m_screensaverIdInUse.empty())
410 return;
412 else if (CServiceBroker::GetAddonMgr().GetAddon(m_screensaverIdInUse, m_pythonScreenSaver,
413 ADDON::AddonType::SCREENSAVER,
414 ADDON::OnlyEnabled::CHOICE_YES))
416 std::string libPath = m_pythonScreenSaver->LibPath();
417 if (CScriptInvocationManager::GetInstance().HasLanguageInvoker(libPath))
419 CLog::Log(LOGDEBUG, "using python screensaver add-on {}", m_screensaverIdInUse);
421 // Don't allow a previously-scheduled alarm to kill our new screensaver
422 g_alarmClock.Stop(SCRIPT_ALARM, true);
424 if (!CScriptInvocationManager::GetInstance().Stop(libPath))
425 CScriptInvocationManager::GetInstance().ExecuteAsync(
426 libPath,
427 ADDON::AddonPtr(new ADDON::CAddon(dynamic_cast<ADDON::CAddon&>(*m_pythonScreenSaver))));
428 return;
430 m_pythonScreenSaver.reset();
433 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SCREENSAVER);
436 void CApplicationPowerHandling::InhibitScreenSaver(bool inhibit)
438 m_bInhibitScreenSaver = inhibit;
441 bool CApplicationPowerHandling::IsScreenSaverInhibited() const
443 return m_bInhibitScreenSaver;
446 // Global Idle Time in Seconds
447 // idle time will be reset if on any OnKey()
448 // int return: system Idle time in seconds! 0 is no idle!
449 int CApplicationPowerHandling::GlobalIdleTime()
451 if (!m_idleTimer.IsRunning())
452 m_idleTimer.StartZero();
453 return (int)m_idleTimer.GetElapsedSeconds();
456 float CApplicationPowerHandling::NavigationIdleTime()
458 if (!m_navigationTimer.IsRunning())
459 m_navigationTimer.StartZero();
460 return m_navigationTimer.GetElapsedSeconds();
463 void CApplicationPowerHandling::StopShutdownTimer()
465 m_shutdownTimer.Stop();
468 void CApplicationPowerHandling::ResetShutdownTimers()
470 // reset system shutdown timer
471 m_shutdownTimer.StartZero();
473 // delete custom shutdown timer
474 if (g_alarmClock.HasAlarm("shutdowntimer"))
475 g_alarmClock.Stop("shutdowntimer", true);
478 void CApplicationPowerHandling::HandleShutdownMessage()
480 switch (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
481 CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNSTATE))
483 case POWERSTATE_SHUTDOWN:
484 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_POWERDOWN);
485 break;
487 case POWERSTATE_SUSPEND:
488 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_SUSPEND);
489 break;
491 case POWERSTATE_HIBERNATE:
492 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_HIBERNATE);
493 break;
495 case POWERSTATE_QUIT:
496 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_QUIT);
497 break;
499 case POWERSTATE_MINIMIZE:
500 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MINIMIZE);
501 break;
503 default:
504 CLog::Log(LOGERROR, "{}: No valid shutdownstate matched", __FUNCTION__);
505 break;
509 void CApplicationPowerHandling::CheckShutdown()
511 // first check if we should reset the timer
512 const auto& components = CServiceBroker::GetAppComponents();
513 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
514 if (!appPlayer)
515 return;
517 if (m_bInhibitIdleShutdown || appPlayer->IsPlaying() ||
518 appPlayer->IsPausedPlayback() // is something playing?
519 || CMusicLibraryQueue::GetInstance().IsRunning() ||
520 CVideoLibraryQueue::GetInstance().IsRunning() ||
521 CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(
522 WINDOW_DIALOG_PROGRESS) // progress dialog is onscreen
524 !CServiceBroker::GetPVRManager().Get<PVR::GUI::PowerManagement>().CanSystemPowerdown(false))
526 m_shutdownTimer.StartZero();
527 return;
530 float elapsed = m_shutdownTimer.IsRunning() ? m_shutdownTimer.GetElapsedSeconds() : 0.f;
531 if (elapsed > CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
532 CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNTIME) *
535 // Since it is a sleep instead of a shutdown, let's set everything to reset when we wake up.
536 m_shutdownTimer.Stop();
538 // Sleep the box
539 CLog::LogF(LOGDEBUG, "Timer is over (shutdown function: {})",
540 CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
541 CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNSTATE));
542 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_SHUTDOWN);
546 void CApplicationPowerHandling::InhibitIdleShutdown(bool inhibit)
548 m_bInhibitIdleShutdown = inhibit;
551 bool CApplicationPowerHandling::IsIdleShutdownInhibited() const
553 return m_bInhibitIdleShutdown;
556 bool CApplicationPowerHandling::OnSettingChanged(const CSetting& setting)
558 const std::string& settingId = setting.GetId();
560 if (settingId == CSettings::SETTING_SCREENSAVER_MODE)
562 CheckOSScreenSaverInhibitionSetting();
564 else
565 return false;
567 return true;
570 bool CApplicationPowerHandling::OnSettingAction(const CSetting& setting)
572 const std::string& settingId = setting.GetId();
574 if (settingId == CSettings::SETTING_SCREENSAVER_PREVIEW)
575 ActivateScreenSaver(true);
576 else if (settingId == CSettings::SETTING_SCREENSAVER_SETTINGS)
578 ADDON::AddonPtr addon;
579 if (CServiceBroker::GetAddonMgr().GetAddon(
580 CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(
581 CSettings::SETTING_SCREENSAVER_MODE),
582 addon, ADDON::AddonType::SCREENSAVER, ADDON::OnlyEnabled::CHOICE_YES))
583 CGUIDialogAddonSettings::ShowForAddon(addon);
585 else
586 return false;
588 return true;