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.
9 #include "GUIBuiltins.h"
11 #include "ServiceBroker.h"
13 #include "application/ApplicationComponents.h"
14 #include "application/ApplicationPowerHandling.h"
15 #include "dialogs/GUIDialogKaiToast.h"
16 #include "dialogs/GUIDialogNumeric.h"
17 #include "filesystem/Directory.h"
18 #include "guilib/GUIComponent.h"
19 #include "guilib/GUIWindowManager.h"
20 #include "guilib/LocalizeStrings.h"
21 #include "guilib/StereoscopicsManager.h"
22 #include "input/WindowTranslator.h"
23 #include "input/actions/Action.h"
24 #include "input/actions/ActionIDs.h"
25 #include "input/actions/ActionTranslator.h"
26 #include "messaging/ApplicationMessenger.h"
27 #include "settings/AdvancedSettings.h"
28 #include "settings/SettingsComponent.h"
29 #include "utils/AlarmClock.h"
30 #include "utils/RssManager.h"
31 #include "utils/Screenshot.h"
32 #include "utils/StringUtils.h"
33 #include "utils/URIUtils.h"
34 #include "utils/log.h"
35 #include "windows/GUIMediaWindow.h"
37 /*! \brief Execute a GUI action.
38 * \param params The parameters.
39 * \details params[0] = Action to execute.
40 * params[1] = Window to send action to (optional).
42 static int Action(const std::vector
<std::string
>& params
)
44 // try translating the action from our ButtonTranslator
45 unsigned int actionID
;
46 if (CActionTranslator::TranslateString(params
[0], actionID
))
48 int windowID
= params
.size() == 2 ? CWindowTranslator::TranslateWindow(params
[1]) : WINDOW_INVALID
;
49 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_ACTION
, windowID
, -1,
50 static_cast<void*>(new CAction(actionID
)));
56 /*! \brief Activate a window.
57 * \param params The parameters.
58 * \details params[0] = The window name.
59 * params[1] = Window starting folder (optional).
61 * Set the Replace template parameter to true to replace current
64 template<bool Replace
>
65 static int ActivateWindow(const std::vector
<std::string
>& params2
)
67 std::vector
<std::string
> params(params2
);
69 std::string strWindow
;
72 strWindow
= params
[0];
73 params
.erase(params
.begin());
76 // confirm the window destination is valid prior to switching
77 int iWindow
= CWindowTranslator::TranslateWindow(strWindow
);
78 if (iWindow
!= WINDOW_INVALID
)
80 // compare the given directory param with the current active directory
81 // if no directory is given, and you switch from a video window to another
82 // we retain history, so it makes sense to not switch to the same window in
84 bool bIsSameStartFolder
= true;
87 CGUIWindow
*activeWindow
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
88 if (activeWindow
&& activeWindow
->IsMediaWindow())
89 bIsSameStartFolder
= static_cast<CGUIMediaWindow
*>(activeWindow
)->IsSameStartFolder(params
[0]);
92 // activate window only if window and path differ from the current active window
93 if (iWindow
!= CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() || !bIsSameStartFolder
)
95 // if the window doesn't change, make sure it knows it's gonna be replaced
96 // this ensures setting the start directory if we switch paths
97 // if we change windows, that's done anyway
98 if (Replace
&& !params
.empty() &&
99 iWindow
== CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())
100 params
.emplace_back("replace");
102 auto& components
= CServiceBroker::GetAppComponents();
103 const auto appPower
= components
.GetComponent
<CApplicationPowerHandling
>();
104 appPower
->WakeUpScreenSaverAndDPMS();
105 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(iWindow
, params
, Replace
);
111 CLog::Log(LOGERROR
, "Activate/ReplaceWindow called with invalid destination window: {}",
119 /*! \brief Activate a window and give given controls focus.
120 * \param params The parameters.
121 * \details params[0] = The window name.
122 * params[1,...] = Pair of (container ID, focus item).
124 * Set the Replace template parameter to true to replace current
127 template<bool Replace
>
128 static int ActivateAndFocus(const std::vector
<std::string
>& params
)
130 std::string strWindow
= params
[0];
132 // confirm the window destination is valid prior to switching
133 int iWindow
= CWindowTranslator::TranslateWindow(strWindow
);
134 if (iWindow
!= WINDOW_INVALID
)
136 if (iWindow
!= CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())
138 // disable the screensaver
139 auto& components
= CServiceBroker::GetAppComponents();
140 const auto appPower
= components
.GetComponent
<CApplicationPowerHandling
>();
141 appPower
->WakeUpScreenSaverAndDPMS();
142 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(iWindow
, {}, Replace
);
144 unsigned int iPtr
= 1;
145 while (params
.size() > iPtr
+ 1)
147 CGUIMessage
msg(GUI_MSG_SETFOCUS
, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog(),
148 atol(params
[iPtr
].c_str()),
149 (params
.size() >= iPtr
+ 2) ? atol(params
[iPtr
+ 1].c_str())+1 : 0);
150 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
158 CLog::Log(LOGERROR
, "Replace/ActivateWindowAndFocus called with invalid destination window: {}",
164 /*! \brief Start an alarm clock
165 * \param params The parameters.
166 * \details param[0] = name
168 * param[2] = Length in seconds (optional).
169 * param[3] = "silent" to suppress notifications.
170 * param[3] = "loop" to loop the alarm.
172 static int AlarmClock(const std::vector
<std::string
>& params
)
174 // format is alarmclock(name,command[,time,true,false]);
176 if (params
.size() > 2)
178 if (params
[2].find(':') == std::string::npos
)
179 seconds
= static_cast<float>(atoi(params
[2].c_str())*60);
181 seconds
= (float)StringUtils::TimeStringToSeconds(params
[2]);
184 { // check if shutdown is specified in particular, and get the time for it
185 std::string strHeading
;
186 if (StringUtils::EqualsNoCase(params
[0], "shutdowntimer"))
187 strHeading
= g_localizeStrings
.Get(20145);
189 strHeading
= g_localizeStrings
.Get(13209);
191 if( CGUIDialogNumeric::ShowAndGetNumber(strTime
, strHeading
) )
192 seconds
= static_cast<float>(atoi(strTime
.c_str())*60);
198 for (unsigned int i
= 3; i
< params
.size() ; i
++)
200 // check "true" for backward comp
201 if (StringUtils::EqualsNoCase(params
[i
], "true") || StringUtils::EqualsNoCase(params
[i
], "silent"))
203 else if (StringUtils::EqualsNoCase(params
[i
], "loop"))
207 if( g_alarmClock
.IsRunning() )
208 g_alarmClock
.Stop(params
[0],silent
);
209 // no negative times not allowed, loop must have a positive time
210 if (seconds
< 0 || (seconds
== 0 && loop
))
212 g_alarmClock
.Start(params
[0], seconds
, params
[1], silent
, loop
);
217 /*! \brief Cancel an alarm clock.
218 * \param params The parameters.
219 * \details params[0] = "true" to silently cancel alarm (optional).
221 static int CancelAlarm(const std::vector
<std::string
>& params
)
223 bool silent
= (params
.size() > 1 &&
224 (StringUtils::EqualsNoCase(params
[1], "true") ||
225 StringUtils::EqualsNoCase(params
[1], "silent")));
226 g_alarmClock
.Stop(params
[0],silent
);
231 /*! \brief Clear a property in a window.
232 * \param params The parameters.
233 * \details params[0] = The property to clear.
234 * params[1] = The window to clear property in (optional).
236 static int ClearProperty(const std::vector
<std::string
>& params
)
238 CGUIWindow
*window
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow(params
.size() > 1 ? CWindowTranslator::TranslateWindow(params
[1]) : CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog());
240 window
->SetProperty(params
[0],"");
245 /*! \brief Close a dialog.
246 * \param params The parameters.
247 * \details params[0] = "all" to close all dialogs, or dialog name.
248 * params[1] = "true" to force close (skip animations) (optional).
250 static int CloseDialog(const std::vector
<std::string
>& params
)
253 if (params
.size() > 1 && StringUtils::EqualsNoCase(params
[1], "true"))
255 if (StringUtils::EqualsNoCase(params
[0], "all"))
257 CServiceBroker::GetGUI()->GetWindowManager().CloseDialogs(bForce
);
261 int id
= CWindowTranslator::TranslateWindow(params
[0]);
262 CGUIWindow
*window
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow(id
);
263 if (window
&& window
->IsDialog())
264 static_cast<CGUIDialog
*>(window
)->Close(bForce
);
270 /*! \brief Send a notification.
271 * \param params The parameters.
272 * \details params[0] = Notification title.
273 * params[1] = Notification text.
274 * params[2] = Display time in milliseconds (optional).
275 * params[3] = Notification icon (optional).
277 static int Notification(const std::vector
<std::string
>& params
)
279 if (params
.size() < 2)
281 if (params
.size() == 4)
282 CGUIDialogKaiToast::QueueNotification(params
[3],params
[0],params
[1],atoi(params
[2].c_str()));
283 else if (params
.size() == 3)
284 CGUIDialogKaiToast::QueueNotification("",params
[0],params
[1],atoi(params
[2].c_str()));
286 CGUIDialogKaiToast::QueueNotification(params
[0],params
[1]);
291 /*! \brief Refresh RSS feed.
292 * \param params (ignored)
294 static int RefreshRSS(const std::vector
<std::string
>& params
)
296 CRssManager::GetInstance().Reload();
301 /*! \brief Take a screenshot.
302 * \param params The parameters.
303 * \details params[0] = URL to save file to. Blank to use default.
304 * params[1] = "sync" to run synchronously (optional).
306 static int Screenshot(const std::vector
<std::string
>& params
)
310 // get the parameters
311 std::string strSaveToPath
= params
[0];
313 if (params
.size() >= 2)
314 sync
= StringUtils::EqualsNoCase(params
[1], "sync");
316 if (!strSaveToPath
.empty())
318 if (XFILE::CDirectory::Exists(strSaveToPath
))
320 std::string file
= CUtil::GetNextFilename(
321 URIUtils::AddFileToFolder(strSaveToPath
, "screenshot{:05}.png"), 65535);
325 CScreenShot::TakeScreenshot(file
, sync
);
329 CLog::Log(LOGWARNING
, "Too many screen shots or invalid folder {}", strSaveToPath
);
333 CScreenShot::TakeScreenshot(strSaveToPath
, sync
);
337 CScreenShot::TakeScreenshot();
342 /*! \brief Set GUI language.
343 * \param params The parameters.
344 * \details params[0] = The language to use.
346 static int SetLanguage(const std::vector
<std::string
>& params
)
348 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_SETLANGUAGE
, -1, -1, nullptr, params
[0]);
353 /*! \brief Set a property in a window.
354 * \param params The parameters.
355 * \details params[0] = The property to set.
356 * params[1] = The property value.
357 * params[2] = The window to set property in (optional).
359 static int SetProperty(const std::vector
<std::string
>& params
)
361 CGUIWindow
*window
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow(params
.size() > 2 ? CWindowTranslator::TranslateWindow(params
[2]) : CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog());
363 window
->SetProperty(params
[0],params
[1]);
368 /*! \brief Set GUI stereo mode.
369 * \param params The parameters.
370 * \details param[0] = Stereo mode identifier.
372 static int SetStereoMode(const std::vector
<std::string
>& params
)
374 CAction action
= CStereoscopicsManager::ConvertActionCommandToAction("SetStereoMode", params
[0]);
375 if (action
.GetID() != ACTION_NONE
)
376 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_ACTION
, WINDOW_INVALID
, -1,
377 static_cast<void*>(new CAction(action
)));
380 CLog::Log(LOGERROR
, "Builtin 'SetStereoMode' called with unknown parameter: {}", params
[0]);
387 /*! \brief Toggle visualization of dirty regions.
388 * \param params Ignored.
390 static int ToggleDirty(const std::vector
<std::string
>&)
392 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->ToggleDirtyRegionVisualization();
397 // Note: For new Texts with comma add a "\" before!!! Is used for table text.
399 /// \page page_List_of_built_in_functions
400 /// \section built_in_functions_5 GUI built-in's
402 /// -----------------------------------------------------------------------------
409 /// <b>`Action(action[\,window])`</b>
411 /// Executes an action (same as in keymap) for the given window or the
412 /// active window if the parameter window is omitted. The parameter window
413 /// can either be the window's id\, or in the case of a standard window\, the
414 /// window's name. See here for a list of window names\, and their respective
416 /// @param[in] action Action to execute.
417 /// @param[in] window Window to send action to (optional).
420 /// <b>`CancelAlarm(name[\,silent])`</b>
422 /// Cancel a running alarm. Set silent to true to hide the alarm notification.
423 /// @param[in] silent Send "true" or "silent" to silently cancel alarm (optional).
426 /// <b>`AlarmClock(name\,command[\,time\,silent\,loop])`</b>
428 /// Pops up a dialog asking for the length of time for the alarm (unless the
429 /// parameter time is specified)\, and starts a timer. When the timer runs out\,
430 /// it'll execute the built-in command (the parameter command) if it is
431 /// specified\, otherwise it'll pop up an alarm notice. Add silent to hide the
432 /// alarm notification. Add loop for the alarm to execute the command each
433 /// time the specified time interval expires.
434 /// @note if using any of the last optional parameters (silent or loop)\, both must
435 /// be provided for any to take effect.
438 /// The following example will create an alarmclock named `mytimer` which will silently
439 /// fire (a single time) and set a property (timerelapsed) with value 1 in the window with
440 /// id 1109 after 5 seconds have passed.
442 /// AlarmClock(mytimer\,SetProperty(timerelapsed\,1\,1109)\,00:00:05\,silent\,false])
445 /// @param[in] name name
446 /// @param[in] command command
447 /// @param[in] time [opt] <b>(a)</b> Length in minutes or <b>(b)</b> a timestring in the format `hh:mm:ss` or `mm min`.
448 /// @param[in] silent [opt] Send "silent" to suppress notifications.
449 /// @param[in] loop [opt] Send "loop" to loop the alarm.
452 /// <b>`ActivateWindow(window[\,dir\, return])`</b>
454 /// Opens the given window. The parameter window can either be the window's id\,
455 /// or in the case of a standard window\, the window's name. See \ref window_ids "here" for a list
456 /// of window names\, and their respective ids.
457 /// If\, furthermore\, the window is
458 /// Music\, Video\, Pictures\, or Program files\, then the optional dir parameter
459 /// specifies which folder Kodi should default to once the window is opened.
460 /// This must be a source as specified in sources.xml\, or a subfolder of a
461 /// valid source. For some windows (MusicLibrary and VideoLibrary)\, a third
462 /// parameter (return) may be specified\, which indicates that Kodi should use this
463 /// folder as the "root" of the level\, and thus the "parent directory" action
464 /// from within this folder will return the user to where they were prior to
465 /// the window activating.
466 /// @param[in] window The window name.
467 /// @param[in] dir Window starting folder (optional).
468 /// @param[in] return if dir should be used as the rootfolder of the level
471 /// <b>`ActivateWindowAndFocus(id1\, id2\,item1\, id3\,item2)`</b>
473 /// Activate window with id1\, first focus control id2 and then focus control
474 /// id3. if either of the controls is a container\, you can specify which
475 /// item to focus (else\, set it to 0).
476 /// @param[in] id1 The window name.
477 /// @param[in] params[1\,...] Pair of (container ID\, focus item).
480 /// <b>`ClearProperty(key[\,id])`</b>
482 /// Clears a window property for the current focused window/dialog(key)\, or
483 /// the specified window (key\,id).
484 /// @param[in] key The property to clear.
485 /// @param[in] id The window to clear property in (optional).
488 /// <b>`Dialog.Close(dialog[\,force])`</b>
490 /// Close a dialog. Set force to true to bypass animations. Use (all\,true)
491 /// to close all opened dialogs at once.
492 /// @param[in] dialog Send "all" to close all dialogs\, or dialog name.
493 /// @param[in] force Send "true" to force close (skip animations) (optional).
496 /// <b>`Notification(header\,message[\,time\,image])`</b>
498 /// Will display a notification dialog with the specified header and message\,
499 /// in addition you can set the length of time it displays in milliseconds
500 /// and a icon image.
501 /// @param[in] header Notification title.
502 /// @param[in] message Notification text.
503 /// @param[in] time Display time in milliseconds (optional).
504 /// @param[in] image Notification icon (optional).
507 /// <b>`RefreshRSS`</b>
509 /// Reload RSS feeds from RSSFeeds.xml
512 /// <b>`ReplaceWindow(window\,dir)`</b>
514 /// Replaces the current window with the given window. This is the same as
515 /// ActivateWindow() but it doesn't update the window history list\, so when
516 /// you go back from the new window it will not return to the previous
517 /// window\, rather will return to the previous window's previous window.
518 /// @param[in] window The window name.
519 /// @param[in] dir Window starting folder (optional).
522 /// <b>`ReplaceWindowAndFocus(id1\, id2\,item1\, id3\,item2)`</b>
524 /// Replace window with id1\, first focus control id2 and then focus control
525 /// id3. if either of the controls is a container\, you can specify which
526 /// item to focus (else\, set it to 0).
527 /// @param[in] id1 The window name.
528 /// @param[in] params[1\,...] Pair of (container ID\, focus item).
531 /// <b>`Resolution(resIdent)`</b>
533 /// Change Kodi's Resolution (default is 4x3).
534 /// param[in] resIdent A resolution identifier.
535 /// | | Identifiers | |
536 /// |:--------:|:-----------:|:--------:|
537 /// | pal | pal16x9 | ntsc |
538 /// | ntsc16x9 | 720p | 720psbs |
539 /// | 720ptb | 1080psbs | 1080ptb |
543 /// <b>`SetGUILanguage(lang)`</b>
546 /// @param[in] lang The language to use.
549 /// <b>`SetProperty(key\,value[\,id])`</b>
551 /// Sets a window property for the current window (key\,value)\, or the
552 /// specified window (key\,value\,id).
553 /// @param[in] key The property to set.
554 /// @param[in] value The property value.
555 /// @param[in] id The window to set property in (optional).
558 /// <b>`SetStereoMode(ident)`</b>
560 /// Changes the stereo mode of the GUI.
562 /// toggle\, next\, previous\, select\, tomono or any of the supported stereomodes (off\,
563 /// split_vertical\, split_horizontal\, row_interleaved\, hardware_based\, anaglyph_cyan_red\, anaglyph_green_magenta\, monoscopic)
564 /// @param[in] ident Stereo mode identifier.
567 /// <b>`TakeScreenshot(url[\,sync)`</b>
569 /// Takes a Screenshot
570 /// @param[in] url URL to save file to. Blank to use default.
571 /// @param[in] sync Add "sync" to run synchronously (optional).
574 /// <b>`ToggleDirtyRegionVisualization`</b>
576 /// makes dirty regions visible for debugging proposes.
581 CBuiltins::CommandMap
CGUIBuiltins::GetOperations() const
584 {"action", {"Executes an action for the active window (same as in keymap)", 1, Action
}},
585 {"cancelalarm", {"Cancels an alarm", 1, CancelAlarm
}},
586 {"alarmclock", {"Prompt for a length of time and start an alarm clock", 2, AlarmClock
}},
587 {"activatewindow", {"Activate the specified window", 1, ActivateWindow
<false>}},
588 {"activatewindowandfocus", {"Activate the specified window and sets focus to the specified id", 1, ActivateAndFocus
<false>}},
589 {"clearproperty", {"Clears a window property for the current focused window/dialog (key,value)", 1, ClearProperty
}},
590 {"dialog.close", {"Close a dialog", 1, CloseDialog
}},
591 {"notification", {"Shows a notification on screen, specify header, then message, and optionally time in milliseconds and a icon.", 2, Notification
}},
592 {"refreshrss", {"Reload RSS feeds from RSSFeeds.xml", 0, RefreshRSS
}},
593 {"replacewindow", {"Replaces the current window with the new one", 1, ActivateWindow
<true>}},
594 {"replacewindowandfocus", {"Replaces the current window with the new one and sets focus to the specified id", 1, ActivateAndFocus
<true>}},
595 {"setguilanguage", {"Set GUI Language", 1, SetLanguage
}},
596 {"setproperty", {"Sets a window property for the current focused window/dialog (key,value)", 2, SetProperty
}},
597 {"setstereomode", {"Changes the stereo mode of the GUI. Params can be: toggle, next, previous, select, tomono or any of the supported stereomodes (off, split_vertical, split_horizontal, row_interleaved, hardware_based, anaglyph_cyan_red, anaglyph_green_magenta, anaglyph_yellow_blue, monoscopic)", 1, SetStereoMode
}},
598 {"takescreenshot", {"Takes a Screenshot", 0, Screenshot
}},
599 {"toggledirtyregionvisualization", {"Enables/disables dirty-region visualization", 0, ToggleDirty
}}