MythTV  master
mythfrontend/exitprompt.cpp
Go to the documentation of this file.
1 #include "config.h"
2 
3 #include <QCoreApplication>
4 #if CONFIG_QTDBUS
5 #include <QtDBus>
6 #include <QDBusInterface>
7 #endif
8 
9 #include "exitprompt.h"
10 #include "mythcontext.h"
11 #include "mythdialogbox.h"
12 #include "mythmainwindow.h"
13 #include "mythscreenstack.h"
14 #include "mythsystemlegacy.h"
15 #include "mythlogging.h"
16 #include "exitcodes.h"
17 
19 {
20  qApp->exit();
21 }
22 
23 static bool DBusHalt(void)
24 {
25 #if CONFIG_QTDBUS
26  QDBusInterface kde("org.kde.ksmserver",
27  "/KSMServer",
28  "org.kde.KSMServerInterface");
29  QDBusInterface gnome("org.gnome.SessionManager",
30  "/org/gnome/SessionManager",
31  "org.gnome.SessionManager");
32  QDBusInterface consolekit("org.freedesktop.ConsoleKit",
33  "/org/freedesktop/ConsoleKit/Manager",
34  "org.freedesktop.ConsoleKit.Manager",
35  QDBusConnection::systemBus());
36  QDBusInterface logind("org.freedesktop.login1",
37  "/org/freedesktop/login1",
38  "org.freedesktop.login1.Manager",
39  QDBusConnection::systemBus());
40  QDBusInterface hal("org.freedesktop.Hal",
41  "/org/freedesktop/Hal/devices/computer",
42  "org.freedesktop.Hal.Device.SystemPowerManagement",
43  QDBusConnection::systemBus());
44 
45  QDBusReply<void> void_reply = kde.call("logout", 0, 2, 2);
46  QDBusReply<bool> bool_reply;
47  QDBusReply<int> int_reply;
48  QDBusReply<QString> string_reply;
49 
50  if (!void_reply.isValid())
51  {
52  bool_reply = logind.call("CanPowerOff");
53  if (string_reply.isValid() && string_reply.value() == "yes")
54  void_reply = logind.call("PowerOff", false);
55  }
56  if (!void_reply.isValid())
57  {
58  bool_reply = gnome.call("CanShutdown");
59  if (bool_reply.isValid() && bool_reply.value())
60  void_reply = gnome.call("RequestShutdown");
61  }
62  if (!void_reply.isValid())
63  {
64  bool_reply = consolekit.call("CanStop");
65  if (bool_reply.isValid() && bool_reply.value())
66  void_reply = consolekit.call("Stop");
67  }
68  if (!void_reply.isValid())
69  int_reply = hal.call("Shutdown");
70 
71  return void_reply.isValid() || int_reply.isValid();
72 #else
73  return false;
74 #endif
75 }
76 
78 {
79  confirm(HALT);
80 }
81 
82 void ExitPrompter::halt(bool Confirmed)
83 {
84  if (!Confirmed)
85  return;
86 
87  QString halt_cmd = gCoreContext->GetSetting("HaltCommand","");
88  int ret = -1;
89 
90  if (!halt_cmd.isEmpty()) /* Use user specified command if it exists */
91  {
92  ret = myth_system(halt_cmd);
93  if (ret != GENERIC_EXIT_OK)
94  {
95  LOG(VB_GENERAL, LOG_ERR,
96  "User defined HaltCommand failed, falling back to "
97  "alternative methods.");
98  }
99  }
100 
101  /* If supported, use DBus to shutdown */
102  if (ret != GENERIC_EXIT_OK && !DBusHalt())
103  myth_system("sudo /sbin/halt -p");
104 }
105 
106 static bool DBusReboot(void)
107 {
108 #if CONFIG_QTDBUS
109  QDBusInterface kde("org.kde.ksmserver",
110  "/KSMServer",
111  "org.kde.KSMServerInterface");
112  QDBusInterface gnome("org.gnome.SessionManager",
113  "/org/gnome/SessionManager",
114  "org.gnome.SessionManager");
115  QDBusInterface consolekit("org.freedesktop.ConsoleKit",
116  "/org/freedesktop/ConsoleKit/Manager",
117  "org.freedesktop.ConsoleKit.Manager",
118  QDBusConnection::systemBus());
119  QDBusInterface hal("org.freedesktop.Hal",
120  "/org/freedesktop/Hal/devices/computer",
121  "org.freedesktop.Hal.Device.SystemPowerManagement",
122  QDBusConnection::systemBus());
123 
124  QDBusReply<void> void_reply = kde.call("logout", 0, 1, 2);
125  QDBusReply<bool> bool_reply;
126  QDBusReply<int> int_reply;
127 
128  if (!void_reply.isValid())
129  {
130  bool_reply = gnome.call("CanShutdown");
131  if (bool_reply.isValid() && bool_reply.value())
132  void_reply=gnome.call("RequestReboot");
133  }
134  if (!void_reply.isValid())
135  {
136  bool_reply = consolekit.call("CanRestart");
137  if (bool_reply.isValid() && bool_reply.value())
138  void_reply = consolekit.call("Restart");
139  }
140  if (!void_reply.isValid())
141  int_reply = hal.call("Reboot");
142 
143  return void_reply.isValid() || int_reply.isValid();
144 #else
145  return false;
146 #endif
147 }
148 
150 {
151  confirm(REBOOT);
152 }
153 
154 void ExitPrompter::reboot(bool Confirmed)
155 {
156  if (!Confirmed)
157  return;
158 
159  QString reboot_cmd = gCoreContext->GetSetting("RebootCommand","");
160  int ret = -1;
161 
162  if (!reboot_cmd.isEmpty()) /* Use user specified command if it exists */
163  {
164  ret = myth_system(reboot_cmd);
165  if (ret != GENERIC_EXIT_OK)
166  {
167  LOG(VB_GENERAL, LOG_ERR,
168  "User defined RebootCommand failed, falling back to "
169  "alternative methods.");
170  }
171  }
172 
173  /* If supported, use DBus to reboot */
174  if (ret != GENERIC_EXIT_OK && !DBusReboot())
175  myth_system("sudo /sbin/reboot");
176 }
177 
179 {
181 }
182 
184 {
185  // HACK IsFrontendOnly() triggers a popup if there is no BE connection.
186  // We really don't need that right now. This hack prevents it.
188 
189  // first of all find out, if this is a frontend only host...
190  bool frontendOnly = gCoreContext->IsFrontendOnly();
191 
192  // HACK Undo the hack, just in case we _don't_ quit:
194 
195 
196  // how do you want to quit today?
197  bool allowExit = false;
198  bool allowReboot = false;
199  bool allowShutdown = false;
200  bool allowStandby = false;
201 
202  switch (gCoreContext->GetNumSetting("OverrideExitMenu", 0))
203  {
204  case 0:
205  allowExit = true;
206  if (frontendOnly)
207  allowShutdown = true;
208  break;
209  case 1:
210  allowExit = true;
211  break;
212  case 2:
213  allowExit = true;
214  allowShutdown = true;
215  break;
216  case 3:
217  allowExit = true;
218  allowReboot = true;
219  allowShutdown = true;
220  break;
221  case 4:
222  allowShutdown = true;
223  break;
224  case 5:
225  allowReboot = true;
226  break;
227  case 6:
228  allowReboot = true;
229  allowShutdown = true;
230  break;
231  case 7:
232  allowStandby = true;
233  break;
234  }
235 
236  MythScreenStack *ss = GetMythMainWindow()->GetStack("popup stack");
237  auto *dlg = new MythDialogBox(tr("Do you really want to exit MythTV?"), ss,
238  "exit prompt");
239 
240  if (!dlg->Create())
241  {
242  LOG(VB_GENERAL, LOG_ERR, "Can't create Exit Prompt dialog?");
243  delete dlg;
244  quit();
245  return;
246  }
247 
248  dlg->AddButton(QCoreApplication::translate("(Common)", "No"));
249  if (allowExit)
250  dlg->AddButton(tr("Yes, Exit now"), SLOT(quit()));
251  if (allowReboot)
252  {
253  dlg->AddButton(tr("Yes, Exit and Reboot"),
254  frontendOnly ? SLOT(reboot()) : SLOT(confirmReboot()));
255  }
256  if (allowShutdown)
257  {
258  dlg->AddButton(tr("Yes, Exit and Shutdown"),
259  frontendOnly ? SLOT(halt()) : SLOT(confirmHalt()));
260  }
261  if (allowStandby)
262  dlg->AddButton(tr("Yes, Enter Standby Mode"), SLOT(standby()));
263 
264  // This is a hack so that the button clicks target the correct slot:
265  dlg->SetReturnEvent(this, QString());
266 
267  ss->AddScreen(dlg);
268 }
269 
271 {
272  MythScreenStack *ss = GetMythMainWindow()->GetStack("popup stack");
273  auto *dlg = new MythConfirmationDialog(ss,
274  tr("Mythbackend is running on this system. Are you sure you want to continue?"));
275 
276  if (!dlg->Create())
277  {
278  delete dlg;
279  quit();
280  return;
281  }
282 
283  if (Action == HALT)
284  connect(dlg, SIGNAL(haveResult(bool)), SLOT(halt(bool)));
285  else if (Action == REBOOT)
286  connect(dlg, SIGNAL(haveResult(bool)), SLOT(reboot(bool)));
287 
288  ss->AddScreen(dlg);
289 }
#define REBOOT
Dialog asking for user confirmation.
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
Basic menu dialog, message and a list of options.
static void standby(void)
MythScreenStack * GetStack(const QString &stackname)
void SetDisableEventPopup(bool check)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static void quit(void)
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:62
An action (for this plugin) consists of a description, and a set of key sequences.
Definition: action.h:40
static bool DBusReboot(void)
void confirm(int Action)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
#define HALT
static void halt(bool Confirmed=true)
QString GetSetting(const QString &key, const QString &defaultval="")
static bool DBusHalt(void)
uint myth_system(const QString &command, uint flags, uint timeout)
MythMainWindow * GetMythMainWindow(void)
int GetNumSetting(const QString &key, int defaultval=0)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static void reboot(bool Confirmed=true)
bool IsFrontendOnly(void)
is there a frontend, but no backend, running on this host