MythTV  master
Engine.cpp
Go to the documentation of this file.
1 /* Engine.cpp
2 
3  Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 2
8  of the License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  Or, point your browser to http://www.gnu.org/copyleft/gpl.html
19 
20 */
21 
22 #include <QStringList>
23 #include <QRegExp>
24 #include <QThread>
25 
26 #include "Engine.h"
27 #include "ParseNode.h"
28 #include "ParseBinary.h"
29 #include "ParseText.h"
30 #include "Root.h"
31 #include "Groups.h"
32 #include "ASN1Codes.h"
33 #include "Logging.h"
34 #include "freemheg.h"
35 #include "Visible.h" // For MHInteractible
36 #include "Stream.h"
37 
38 #include <cstdarg>
39 #include <cstdio>
40 #include <cstdlib>
41 
42 // External creation function.
44 {
45  return new MHEngine(context);
46 }
47 
48 MHEngine::MHEngine(MHContext *context): m_Context(context)
49 {
50  // Required for BBC Freeview iPlayer
51  auto *pEntry = new MHPSEntry;
52  pEntry->m_FileName.Copy("ram://bbcipstr");
53  pEntry->m_Data.Append(new MHUnion(true)); // Default true
54  // The next value must be true to enable Freeview interaction channel
55  pEntry->m_Data.Append(new MHUnion(true)); // Default false
56  m_PersistentStore.Append(pEntry);
57 }
58 
60 {
61  while (!m_ApplicationStack.isEmpty())
62  {
63  delete m_ApplicationStack.pop();
64  }
65 
66  while (!m_EventQueue.isEmpty())
67  {
68  delete m_EventQueue.dequeue();
69  }
70 
71  while (!m_ExternContentTable.isEmpty())
72  {
73  delete m_ExternContentTable.takeFirst();
74  }
75 }
76 
77 // Check for external content every 2 seconds.
78 #define CONTENT_CHECK_TIME 2000
79 
80 // This is the main loop of the engine.
82 {
83  // Request to boot or reboot
84  if (m_fBooting)
85  {
86  // Reset everything
87  while (!m_ApplicationStack.isEmpty())
88  {
89  delete m_ApplicationStack.pop();
90  }
91 
92  while (!m_EventQueue.isEmpty())
93  {
94  delete m_EventQueue.dequeue();
95  }
96 
97  while (!m_ExternContentTable.isEmpty())
98  {
99  delete m_ExternContentTable.takeFirst();
100  }
101 
102  m_LinkTable.clear();
103 
104  // UK MHEG applications boot from ~//a or ~//startup. Actually the initial
105  // object can also be explicitly given in the
106  MHObjectRef startObj;
107  startObj.m_nObjectNo = 0;
108  startObj.m_GroupId.Copy(MHOctetString("~//a"));
109 
110  // Launch will block until either it finds the appropriate object and
111  // begins the application or discovers that the file definitely isn't
112  // present in the carousel. It is possible that the object might appear
113  // if one of the containing directories is updated.
114  if (! Launch(startObj))
115  {
116  startObj.m_GroupId.Copy(MHOctetString("~//startup"));
117 
118  if (! Launch(startObj))
119  {
120  MHLOG(MHLogNotifications, "NOTE Engine auto-boot failed");
121  return -1;
122  }
123  }
124 
125  m_fBooting = false;
126  }
127 
128  int nNextTime = 0;
129 
130  do
131  {
132  // Check to see if we need to close.
133  if (m_Context->CheckStop())
134  {
135  return 0;
136  }
137 
138  // Run queued actions.
139  RunActions();
140  // Now the action stack is empty process the next asynchronous event.
141  // Processing one event may affect how subsequent events are handled.
142 
143  // Check to see if some files we're waiting for have arrived.
144  // This could result in ContentAvailable events.
146 
147  // Check the timers. This may result in timer events being raised.
148  nNextTime = CurrentScene() ? CurrentScene()->CheckTimers(this) : 0;
149 
150  if (CurrentApp())
151  {
152  // The UK MHEG profile allows applications to have timers.
153  int nAppTime = CurrentApp()->CheckTimers(this);
154 
155  if (nAppTime != 0 && (nNextTime == 0 || nAppTime < nNextTime))
156  {
157  nNextTime = nAppTime;
158  }
159  }
160 
161  if (! m_ExternContentTable.isEmpty())
162  {
163  // If we have an outstanding request for external content we need to set a timer.
164  if (nNextTime == 0 || nNextTime > CONTENT_CHECK_TIME)
165  {
166  nNextTime = CONTENT_CHECK_TIME;
167  }
168  }
169 
170  if (! m_EventQueue.isEmpty())
171  {
172  MHAsynchEvent *pEvent = m_EventQueue.dequeue();
173  MHLOG(MHLogLinks, QString("Asynchronous event dequeued - %1 from %2")
175  .arg(pEvent->m_pEventSource->m_ObjectReference.Printable()));
177  pEvent->m_eventType, pEvent->m_eventData);
178  delete pEvent;
179  }
180  }
181  while (! m_EventQueue.isEmpty() || ! m_ActionStack.isEmpty());
182 
183  // Redraw the display if necessary.
184  if (! m_redrawRegion.isEmpty())
185  {
187  m_redrawRegion = QRegion();
188  }
189 
190  return nNextTime;
191 }
192 
193 
194 // Convert the parse tree for an application or scene into an object node.
195 MHGroup *MHEngine::ParseProgram(QByteArray &text)
196 {
197  if (text.size() == 0)
198  {
199  return nullptr;
200  }
201 
202  // Look at the first byte to decide whether this is text or binary. Binary
203  // files will begin with 0xA0 or 0xA1, text files with white space, comment ('/')
204  // or curly bracket.
205  // This is only there for testing: all downloaded objects will be in ASN1
206  unsigned char ch = text[0];
207  MHParseBase *parser = nullptr;
208  MHParseNode *pTree = nullptr;
209  MHGroup *pRes = nullptr;
210 
211  if (ch >= 128)
212  {
213  parser = new MHParseBinary(text);
214  }
215  else
216  {
217  parser = new MHParseText(text);
218  }
219 
220  try
221  {
222  // Parse the binary or text.
223  pTree = parser->Parse();
224 
225  switch (pTree->GetTagNo()) // The parse node should be a tagged item.
226  {
227  case C_APPLICATION:
228  pRes = new MHApplication;
229  break;
230  case C_SCENE:
231  pRes = new MHScene;
232  break;
233  default:
234  MHParseNode::Failure("Expected Application or Scene"); // throws exception.
235  }
236 
237  pRes->Initialise(pTree, this); // Convert the parse tree.
238  delete(pTree);
239  delete(parser);
240  }
241  catch (...)
242  {
243  delete(parser);
244  delete(pTree);
245  delete(pRes);
246  throw;
247  }
248 
249  return pRes;
250 }
251 
252 // Determine protocol for a file
254 static EProtocol PathProtocol(const QString& csPath)
255 {
256  if (csPath.isEmpty() || csPath.startsWith("DSM:") || csPath.startsWith("~"))
257  return kProtoDSM;
258  if (csPath.startsWith("hybrid:"))
259  return kProtoHybrid;
260  if (csPath.startsWith("http:") || csPath.startsWith("https:"))
261  return kProtoHTTP;
262  if (csPath.startsWith("CI:"))
263  return kProtoCI;
264 
265  int firstColon = csPath.indexOf(':');
266  int firstSlash = csPath.indexOf('/');
267  if (firstColon > 0 && firstSlash > 0 && firstColon < firstSlash)
268  return kProtoUnknown;
269 
270  return kProtoDSM;
271 }
272 
273 // Launch and Spawn
274 bool MHEngine::Launch(const MHObjectRef &target, bool fIsSpawn)
275 {
276  if (m_fInTransition)
277  {
278  MHLOG(MHLogWarning, "WARN Launch during transition - ignoring");
279  return false;
280  }
281 
282  if (target.m_GroupId.Size() == 0) return false; // No file name.
283  QString csPath = GetPathName(target.m_GroupId); // Get path relative to root.
284  MHLOG(MHLogNotifications, "NOTE Launching " + csPath);
285 
286  // Check that the file exists before we commit to the transition.
287  // This may block if we cannot be sure whether the object is present.
288  QByteArray text;
289  if (! m_Context->GetCarouselData(csPath, text))
290  {
291  if (!m_fBooting)
292  EngineEvent(2); // GroupIDRefError
293  MHLOG(MHLogWarning, "WARN Launch not found " + csPath);
294  return false;
295  }
296 
297  auto *pProgram = dynamic_cast<MHApplication*>(ParseProgram(text));
298  if (! pProgram)
299  {
300  MHLOG(MHLogWarning, "Empty application");
301  return false;
302  }
303  if (! pProgram->m_fIsApp)
304  {
305  MHLOG(MHLogWarning, "Expected an application");
306  delete pProgram;
307  return false;
308  }
309  if ((__mhlogoptions & MHLogScenes) && __mhlogStream != nullptr) // Print it so we know what's going on.
310  {
311  pProgram->PrintMe(__mhlogStream, 0);
312  }
313 
314  // Clear the action queue of anything pending.
315  m_ActionStack.clear();
316 
317  m_fInTransition = true; // Starting a transition
318 
319  try
320  {
321  if (CurrentApp())
322  {
323  if (fIsSpawn) // Run the CloseDown actions.
324  {
325  AddActions(CurrentApp()->m_CloseDown);
326  RunActions();
327  }
328 
329  if (CurrentScene())
330  {
331  CurrentScene()->Destruction(this);
332  }
333 
334  CurrentApp()->Destruction(this);
335 
336  if (!fIsSpawn)
337  {
338  delete m_ApplicationStack.pop(); // Pop and delete the current app.
339  }
340  }
341 
342  // Save the path we use for this app.
343  pProgram->m_Path = csPath; // Record the path
344  int nPos = pProgram->m_Path.lastIndexOf('/');
345 
346  if (nPos < 0)
347  {
348  pProgram->m_Path = "";
349  }
350  else
351  {
352  pProgram->m_Path = pProgram->m_Path.left(nPos);
353  }
354 
355  // Have now got the application.
356  m_ApplicationStack.push(pProgram);
357 
358  // This isn't in the standard as far as I can tell but we have to do this because
359  // we may have events referring to the old application.
360  while (!m_EventQueue.isEmpty())
361  {
362  delete m_EventQueue.dequeue();
363  }
364 
365  // Activate the application. ....
366  CurrentApp()->Activation(this);
367  m_fInTransition = false; // The transition is complete
368  MHLOG(MHLogNotifications, "NOTE Launch completed OK");
369  return true;
370  }
371  catch (...)
372  {
373  m_fInTransition = false; // The transition is complete
374  return false;
375  }
376 }
377 
379 {
380  if (m_fInTransition)
381  {
382  MHLOG(MHLogWarning, "WARN Quit during transition - ignoring");
383  return;
384  }
385 
386  m_fInTransition = true; // Starting a transition
387 
388  if (CurrentScene())
389  {
390  CurrentScene()->Destruction(this);
391  }
392 
393  CurrentApp()->Destruction(this);
394 
395  // This isn't in the standard as far as I can tell but we have to do this because
396  // we may have events referring to the old application.
397  while (!m_EventQueue.isEmpty())
398  {
399  delete m_EventQueue.dequeue();
400  }
401 
402  delete m_ApplicationStack.pop();
403 
404  // If the stack is now empty we return to boot mode.
405  if (m_ApplicationStack.isEmpty())
406  {
407  m_fBooting = true;
408  }
409  else
410  {
411  CurrentApp()->m_fRestarting = true;
412  CurrentApp()->Activation(this); // This will do any OnRestart actions.
413  // Note - this doesn't activate the previously active scene.
414  }
415 
416  m_fInTransition = false; // The transition is complete
417 }
418 
420 {
421  if (m_fInTransition)
422  {
423  // TransitionTo is not allowed in OnStartUp or OnCloseDown actions.
424  MHLOG(MHLogWarning, "WARN TransitionTo during transition - ignoring");
425  return;
426  }
427 
428  if (target.m_GroupId.Size() == 0)
429  {
430  return; // No file name.
431  }
432 
433  QString csPath = GetPathName(target.m_GroupId);
434 
435  // Check that the file exists before we commit to the transition.
436  // This may block if we cannot be sure whether the object is present.
437  QByteArray text;
438  if (! m_Context->GetCarouselData(csPath, text)) {
439  EngineEvent(2); // GroupIDRefError
440  return;
441  }
442 
443  // Parse and run the file.
444  MHGroup *pProgram = ParseProgram(text);
445 
446  if (!pProgram )
447  MHERROR("Empty scene");
448 
449  if (pProgram->m_fIsApp)
450  {
451  delete pProgram;
452  MHERROR("Expected a scene");
453  }
454 
455  // Clear the action queue of anything pending.
456  m_ActionStack.clear();
457 
458  // At this point we have managed to load the scene.
459  // Deactivate any non-shared ingredients in the application.
460  MHApplication *pApp = CurrentApp();
461 
462  for (int i = pApp->m_Items.Size(); i > 0; i--)
463  {
464  MHIngredient *pItem = pApp->m_Items.GetAt(i - 1);
465 
466  if (! pItem->IsShared())
467  {
468  pItem->Deactivation(this); // This does not remove them from the display stack.
469  }
470  }
471 
472  m_fInTransition = true; // TransitionTo etc are not allowed.
473 
474  if (pApp->m_pCurrentScene)
475  {
476  pApp->m_pCurrentScene->Deactivation(this); // This may involve a call to RunActions
477  pApp->m_pCurrentScene->Destruction(this);
478  }
479 
480  // Everything that belongs to the previous scene should have been removed from the display stack.
481 
482  // At this point we may have added actions to the queue as a result of synchronous
483  // events during the deactivation.
484 
485  // Remove any events from the asynch event queue unless they derive from
486  // the application itself or a shared ingredient.
487 
488  // This was causing crashes with leftover events being invalid.
489  // Changed to clear all events at this point.
490 
491  while (!m_EventQueue.isEmpty())
492  delete m_EventQueue.dequeue();
493 
494  // Can now actually delete the old scene.
495  if (pApp->m_pCurrentScene)
496  {
497  delete(pApp->m_pCurrentScene);
498  pApp->m_pCurrentScene = nullptr;
499  }
500 
501  m_Interacting = nullptr;
502 
503  // Switch to the new scene.
504  CurrentApp()->m_pCurrentScene = static_cast< MHScene* >(pProgram);
505  SetInputRegister(CurrentScene()->m_nEventReg);
506  m_redrawRegion = QRegion(0, 0, CurrentScene()->m_nSceneCoordX, CurrentScene()->m_nSceneCoordY); // Redraw the whole screen
507 
508  if ((__mhlogoptions & MHLogScenes) && __mhlogStream != nullptr) // Print it so we know what's going on.
509  {
510  pProgram->PrintMe(__mhlogStream, 0);
511  }
512 
513  pProgram->Preparation(this);
514  pProgram->Activation(this);
515  m_fInTransition = false; // The transition is complete
516 }
517 
519 {
520  m_Context->SetInputRegister(nReg); // Enable the appropriate buttons
521 }
522 
523 // Create a canonical path name. The rules are given in the UK MHEG document.
525 {
526  if (str.Size() == 0)
527  return QString();
528 
529  QString csPath = QString::fromUtf8((const char *)str.Bytes(), str.Size());
530  switch (PathProtocol(csPath))
531  {
532  default:
533  case kProtoUnknown:
534  case kProtoHybrid:
535  case kProtoHTTP:
536  case kProtoCI:
537  return csPath;
538  case kProtoDSM:
539  break;
540  }
541 
542  if (csPath.startsWith("DSM:"))
543  csPath = csPath.mid(4); // Remove DSM:
544  else if (csPath.startsWith("~"))
545  csPath = csPath.mid(1); // Remove ~
546  if (!csPath.startsWith("//"))
547  {
548  // Add the current application's path name
549  if (CurrentApp())
550  {
551  csPath = CurrentApp()->m_Path + csPath;
552  }
553  }
554 
555  // Remove any occurrences of x/../
556  int nPos = -1;
557 
558  while ((nPos = csPath.indexOf("/../")) >= 0)
559  {
560  int nEnd = nPos + 4;
561 
562  while (nPos >= 1 && csPath[nPos-1] != '/')
563  {
564  nPos--;
565  }
566 
567  csPath = csPath.left(nPos) + csPath.mid(nEnd);
568  }
569 
570  return csPath;
571 }
572 
573 // Look up an object. In most cases we just want to fail if the object isn't found.
574 MHRoot *MHEngine::FindObject(const MHObjectRef &oRef, bool failOnNotFound)
575 {
576  // It should match either the application or the scene.
577  MHGroup *pSearch = nullptr;
578  MHGroup *pScene = CurrentScene();
579  MHGroup *pApp = CurrentApp();
580 
581  if (pScene && GetPathName(pScene->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
582  {
583  pSearch = pScene;
584  }
585  else if (pApp && GetPathName(pApp->m_ObjectReference.m_GroupId) == GetPathName(oRef.m_GroupId))
586  {
587  pSearch = pApp;
588  }
589 
590  if (pSearch)
591  {
592  MHRoot *pItem = pSearch->FindByObjectNo(oRef.m_nObjectNo);
593 
594  if (pItem)
595  {
596  return pItem;
597  }
598  }
599 
600  if (failOnNotFound)
601  {
602  // I've seen at least one case where MHEG code has quite deliberately referred to
603  // an object that may or may not exist at a particular time.
604  // Another case was a call to CallActionSlot with an object reference variable
605  // that had been initialised to zero.
606  MHLOG(MHLogWarning, QString("WARN Reference %1 not found").arg(oRef.m_nObjectNo));
607  throw "FindObject failed";
608  }
609 
610  return nullptr; // If we don't generate an error.
611 }
612 
613 // Run queued actions.
615 {
616  while (! m_ActionStack.isEmpty())
617  {
618  // Remove the first action.
619  MHElemAction *pAction = m_ActionStack.pop();
620 
621  // Run it. If it fails and throws an exception catch it and continue with the next.
622  try
623  {
624  if ((__mhlogoptions & MHLogActions) && __mhlogStream != nullptr) // Debugging
625  {
626  fprintf(__mhlogStream, "[freemheg] Action - ");
627  pAction->PrintMe(__mhlogStream, 0);
628  fflush(__mhlogStream);
629  }
630 
631  pAction->Perform(this);
632  }
633  catch (...)
634  {
635  }
636  }
637 }
638 
639 // Called when an event is triggered. Either queues the event or finds a link that matches.
640 void MHEngine::EventTriggered(MHRoot *pSource, enum EventType ev, const MHUnion &evData)
641 {
642  MHLOG(MHLogLinks, QString("Event - %1 from %2")
643  .arg(MHLink::EventTypeToString(ev)).arg(pSource->m_ObjectReference.Printable()));
644 
645  switch (ev)
646  {
648  case EventHeadItems:
649  case EventHighlightOff:
650  case EventHighlightOn:
651  case EventIsAvailable:
652  case EventIsDeleted:
653  case EventIsDeselected:
654  case EventIsRunning:
655  case EventIsSelected:
656  case EventIsStopped:
657  case EventItemDeselected:
658  case EventItemSelected:
660  case EventTailItems:
661  case EventTestEvent:
662  case EventTokenMovedFrom:
663  case EventTokenMovedTo:
664  // Synchronous events. Fire any links that are waiting.
665  // The UK MHEG describes this as the preferred interpretation. We are checking the link
666  // at the time we generate the event rather than queuing the synchronous events until
667  // this elementary action is complete. That matters if we are processing an elementary action
668  // which will activate or deactivate links.
669  CheckLinks(pSource->m_ObjectReference, ev, evData);
670  break;
671  case EventAnchorFired:
672  case EventAsyncStopped:
674  case EventCounterTrigger:
675  case EventCursorEnter:
676  case EventCursorLeave:
677  case EventEngineEvent:
678  case EventEntryFieldFull:
680  case EventStreamEvent:
681  case EventStreamPlaying:
682  case EventStreamStopped:
683  case EventTimerFired:
684  case EventUserInput:
685  case EventFocusMoved: // UK MHEG. Generated by HyperText class
686  case EventSliderValueChanged: // UK MHEG. Generated by Slider class
687  default:
688  {
689  // Asynchronous events. Add to the event queue.
690  auto *pEvent = new MHAsynchEvent;
691  pEvent->m_pEventSource = pSource;
692  pEvent->m_eventType = ev;
693  pEvent->m_eventData = evData;
694  m_EventQueue.enqueue(pEvent);
695  }
696  break;
697  }
698 }
699 
700 
701 // TO CHECK: If two actions both depend on the same event is the order in which the links are
702 // searched defined? This processes items in the order in which they were activated rather
703 // than their static position in the group.
704 
705 // Check all the links in the application and scene and fire any that match this event.
706 void MHEngine::CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
707 {
708  foreach (auto link, m_LinkTable)
709  link->MatchEvent(sourceRef, ev, un, this);
710 }
711 
712 // Add and remove links to and from the active link table.
714 {
715  m_LinkTable.append(pLink);
716 }
717 
719 {
720  m_LinkTable.removeAll(pLink);
721 }
722 
723 // Called when a link fires to add the actions to the action stack.
725 {
726  // Put them on the stack in reverse order so that we will pop the first.
727  for (int i = actions.Size(); i > 0; i--)
728  {
729  m_ActionStack.push(actions.GetAt(i - 1));
730  }
731 }
732 
733 // Add a visible to the display stack if it isn't already there.
735 {
736  if (CurrentApp()->FindOnStack(pVis) != -1)
737  {
738  return; // Return if it's already there.
739  }
740 
742  Redraw(pVis->GetVisibleArea()); // Request a redraw
743 }
744 
745 // Remove a visible from the display stack if it is there.
747 {
748  int nPos = CurrentApp()->FindOnStack(pVis);
749 
750  if (nPos == -1)
751  {
752  return;
753  }
754 
756  Redraw(pVis->GetVisibleArea()); // Request a redraw
757 }
758 
759 // Functions to alter the Z-order.
761 {
762  int nPos = CurrentApp()->FindOnStack(p);
763 
764  if (nPos == -1)
765  {
766  return; // If it's not there do nothing
767  }
768 
769  auto *pVis = (MHVisible *)p; // Can now safely cast it.
770  CurrentApp()->m_DisplayStack.RemoveAt(nPos); // Remove it from its present posn
771  CurrentApp()->m_DisplayStack.Append(pVis); // Push it on the top.
772  Redraw(pVis->GetVisibleArea()); // Request a redraw
773 }
774 
776 {
777  int nPos = CurrentApp()->FindOnStack(p);
778 
779  if (nPos == -1)
780  {
781  return; // If it's not there do nothing
782  }
783 
784  auto *pVis = (MHVisible *)p; // Can now safely cast it.
785  CurrentApp()->m_DisplayStack.RemoveAt(nPos); // Remove it from its present posn
786  CurrentApp()->m_DisplayStack.InsertAt(pVis, 0); // Put it on the bottom.
787  Redraw(pVis->GetVisibleArea()); // Request a redraw
788 }
789 
790 void MHEngine::PutBefore(const MHRoot *p, const MHRoot *pRef)
791 {
792  int nPos = CurrentApp()->FindOnStack(p);
793 
794  if (nPos == -1)
795  {
796  return; // If it's not there do nothing
797  }
798 
799  auto *pVis = (MHVisible *)p; // Can now safely cast it.
800  int nRef = CurrentApp()->FindOnStack(pRef);
801 
802  if (nRef == -1)
803  {
804  return; // If the reference visible isn't there do nothing.
805  }
806 
808 
809  if (nRef >= nPos)
810  {
811  nRef--; // The position of the reference may have shifted
812  }
813 
814  CurrentApp()->m_DisplayStack.InsertAt(pVis, nRef + 1);
815  // Redraw the area occupied by the moved item. We might be able to reduce
816  // the area to be redrawn by looking at the way it is affected by other items
817  // in the stack. We could also see whether it's currently active.
818  Redraw(pVis->GetVisibleArea()); // Request a redraw
819 }
820 
821 void MHEngine::PutBehind(const MHRoot *p, const MHRoot *pRef)
822 {
823  int nPos = CurrentApp()->FindOnStack(p);
824 
825  if (nPos == -1)
826  {
827  return; // If it's not there do nothing
828  }
829 
830  int nRef = CurrentApp()->FindOnStack(pRef);
831 
832  if (nRef == -1)
833  {
834  return; // If the reference visible isn't there do nothing.
835  }
836 
837  auto *pVis = (MHVisible *)p; // Can now safely cast it.
839 
840  if (nRef >= nPos)
841  {
842  nRef--; // The position of the reference may have shifted
843  }
844 
845  CurrentApp()->m_DisplayStack.InsertAt(pVis, nRef); // Shift the reference and anything above up.
846  Redraw(pVis->GetVisibleArea()); // Request a redraw
847 }
848 
849 // Draw a region of the screen. This attempts to minimise the drawing by eliminating items
850 // that are completely obscured by items above them. We have to take into account the
851 // transparency of items since items higher up the stack may be semi-transparent.
852 void MHEngine::DrawRegion(const QRegion& toDraw, int nStackPos)
853 {
854  if (toDraw.isEmpty())
855  {
856  return; // Nothing left to draw.
857  }
858 
859  while (nStackPos >= 0)
860  {
861  MHVisible *pItem = CurrentApp()->m_DisplayStack.GetAt(nStackPos);
862  // Work out how much of the area we want to draw is included in this visible.
863  // The visible area will be empty if the item is transparent or not active.
864  QRegion drawArea = pItem->GetVisibleArea() & toDraw;
865 
866  if (! drawArea.isEmpty()) // It contributes something.
867  {
868  // Remove the opaque area of this item from the region we have left.
869  // If this item is (semi-)transparent this will not remove anything.
870  QRegion newDraw = toDraw - pItem->GetOpaqueArea();
871  DrawRegion(newDraw, nStackPos - 1); // Do the items further down if any.
872  // Now we've drawn anything below this we can draw this item on top.
873  pItem->Display(this);
874  return;
875  }
876 
877  nStackPos--;
878  }
879 
880  // We've drawn all the visibles and there's still some undrawn area.
881  // Fill it with black.
882  m_Context->DrawBackground(toDraw);
883 }
884 
885 // Redraw an area of the display. This will be called via the context from Redraw.
886 void MHEngine::DrawDisplay(QRegion toDraw)
887 {
888  if (m_fBooting)
889  {
890  return;
891  }
892 
893  int nTopStack = CurrentApp() == nullptr ? -1 : CurrentApp()->m_DisplayStack.Size() - 1;
894  DrawRegion(toDraw, nTopStack);
895 }
896 
897 // An area of the screen needs to be redrawn. We simply remember this and redraw it
898 // in one go when the timer expires.
899 void MHEngine::Redraw(const QRegion& region)
900 {
901  m_redrawRegion += region;
902 }
903 
904 // Called to decrement the lock count.
906 {
907  if (CurrentApp()->m_nLockCount > 0)
908  {
910  }
911 }
912 
913 
914 // Called from the windowing application, this generates a user event as the result of a button push.
916 {
917  MHScene *pScene = CurrentScene();
918 
919  if (! pScene)
920  {
921  return;
922  }
923 
924  // Various keys generate engine events as well as user events.
925  // These are generated before the user events and even if there
926  // is an interactible.
927  switch (nCode)
928  {
929  case 104:
930  case 105: // Text key
931  EngineEvent(4);
932  break;
933  case 16: // Text Exit/Cancel key
934  case 100: // Red
935  case 101: // Green
936  case 102: // Yellow
937  case 103: // Blue
938  case 300: // EPG
939  EngineEvent(nCode);
940  break;
941  }
942 
943  // If we are interacting with an interactible send the key
944  // there otherwise generate a user event.
945  if (m_Interacting)
946  {
947  m_Interacting->KeyEvent(this, nCode);
948  }
949  else
950  {
951  EventTriggered(pScene, EventUserInput, nCode);
952  }
953 }
954 
955 void MHEngine::EngineEvent(int nCode)
956 {
957  if (CurrentApp())
959  else if (!m_fBooting)
960  MHLOG(MHLogWarning, QString("WARN EngineEvent %1 but no app").arg(nCode));
961 }
962 
963 void MHEngine::StreamStarted(MHStream *stream, bool bStarted)
964 {
966 }
967 
968 // Called by an ingredient wanting external content.
970 {
971  // It seems that some MHEG applications contain active ingredients with empty contents
972  // This isn't correct but we simply ignore that.
973  if (! pRequester->m_ContentRef.IsSet())
974  {
975  return;
976  }
977 
978  // Remove any existing content requests for this ingredient.
979  CancelExternalContentRequest(pRequester);
980 
981  QString csPath = GetPathName(pRequester->m_ContentRef.m_ContentRef);
982 
983  if (csPath.isEmpty())
984  {
985  MHLOG(MHLogWarning, "RequestExternalContent empty path");
986  return;
987  }
988 
989  if (m_Context->CheckCarouselObject(csPath))
990  {
991  // Available now - pass it to the ingredient.
992  QByteArray text;
993  if (m_Context->GetCarouselData(csPath, text))
994  {
995  // If the content is not recognized catch the exception and continue
996  try
997  {
998  pRequester->ContentArrived(
999  reinterpret_cast< const unsigned char * >(text.constData()),
1000  text.size(), this);
1001  }
1002  catch (...)
1003  {}
1004  }
1005  else
1006  {
1007  MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
1008  .arg(pRequester->m_ObjectReference.Printable()).arg(csPath));
1009  if (kProtoHTTP == PathProtocol(csPath))
1010  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1011  EngineEvent(3); // ContentRefError
1012  }
1013  }
1014  else
1015  {
1016  // Need to record this and check later.
1017  MHLOG(MHLogNotifications, QString("Waiting for %1 <= %2")
1018  .arg(pRequester->m_ObjectReference.Printable()).arg(csPath.left(128)) );
1019  auto *pContent = new MHExternContent;
1020  pContent->m_FileName = csPath;
1021  pContent->m_pRequester = pRequester;
1022  pContent->m_time.start();
1023  m_ExternContentTable.append(pContent);
1024  }
1025 }
1026 
1027 // Remove any pending requests from the queue.
1029 {
1030  QList<MHExternContent *>::iterator it = m_ExternContentTable.begin();
1031 
1032  while (it != m_ExternContentTable.end())
1033  {
1034  MHExternContent *pContent = *it;
1035 
1036  if (pContent->m_pRequester == pRequester)
1037  {
1038  MHLOG(MHLogNotifications, QString("Cancelled wait for %1")
1039  .arg(pRequester->m_ObjectReference.Printable()) );
1040  it = m_ExternContentTable.erase(it);
1041  delete pContent;
1042  return;
1043  }
1044  ++it;
1045  }
1046 }
1047 
1048 // See if we can satisfy any of the outstanding requests.
1050 {
1051  QList<MHExternContent*>::iterator it = m_ExternContentTable.begin();
1052  while (it != m_ExternContentTable.end())
1053  {
1054  MHExternContent *pContent = *it;
1055  if (m_Context->CheckCarouselObject(pContent->m_FileName))
1056  {
1057  // Remove from the list.
1058  it = m_ExternContentTable.erase(it);
1059 
1060  QByteArray text;
1061  if (m_Context->GetCarouselData(pContent->m_FileName, text))
1062  {
1063  MHLOG(MHLogNotifications, QString("Received %1 len %2")
1064  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
1065  .arg(text.size()) );
1066  // If the content is not recognized catch the exception and continue
1067  try
1068  {
1069  pContent->m_pRequester->ContentArrived(
1070  reinterpret_cast< const unsigned char * >(text.constData()),
1071  text.size(), this);
1072  }
1073  catch (...)
1074  {}
1075  }
1076  else
1077  {
1078  MHLOG(MHLogWarning, QString("WARN No file content %1 <= %2")
1079  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
1080  .arg(pContent->m_FileName));
1081  if (kProtoHTTP == PathProtocol(pContent->m_FileName))
1082  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1083  EngineEvent(3); // ContentRefError
1084  }
1085 
1086  delete pContent;
1087  }
1088  else if (pContent->m_time.elapsed() > 60000) // TODO Get this from carousel
1089  {
1090  // Remove from the list.
1091  it = m_ExternContentTable.erase(it);
1092 
1093  MHLOG(MHLogWarning, QString("WARN File timed out %1 <= %2")
1094  .arg(pContent->m_pRequester->m_ObjectReference.Printable())
1095  .arg(pContent->m_FileName));
1096 
1097  if (kProtoHTTP == PathProtocol(pContent->m_FileName))
1098  EngineEvent(203); // 203=RemoteNetworkError if 404 reply
1099  EngineEvent(3); // ContentRefError
1100 
1101  delete pContent;
1102  }
1103  else
1104  {
1105  ++it;
1106  }
1107  }
1108 }
1109 
1110 bool MHEngine::LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence<MHObjectRef *> &variables)
1111 {
1112  QString const csFile = QString::fromUtf8(
1113  (const char *)fileName.Bytes(), fileName.Size() );
1114 
1115  // See if there is an entry there already.
1116  MHPSEntry *pEntry = nullptr;
1117  int i = 0;
1118 
1119  for (i = 0; i < m_PersistentStore.Size(); i++)
1120  {
1121  pEntry = m_PersistentStore.GetAt(i);
1122 
1123  if (pEntry->m_FileName.Equal(fileName))
1124  {
1125  break;
1126  }
1127  }
1128 
1129  if (i == m_PersistentStore.Size()) // Not there.
1130  {
1131  // If we're loading then we've failed.
1132  if (fIsLoad)
1133  {
1134  MHLOG(MHLogNotifications, QString(
1135  "Load Persistent(%1) #%2: no such file")
1136  .arg(csFile).arg(variables.Size()) );
1137  return false;
1138  }
1139 
1140  // If we're storing we make a new entry.
1141  pEntry = new MHPSEntry;
1142  pEntry->m_FileName.Copy(fileName);
1143  m_PersistentStore.Append(pEntry);
1144  }
1145 
1146  if (fIsLoad) // Copy the data into the variables.
1147  {
1148  // Check that we have sufficient data before we continue?
1149  if (pEntry->m_Data.Size() < variables.Size())
1150  {
1151  MHLOG(MHLogWarning, QString(
1152  "Load Persistent(%1): size mismatch").arg(csFile));
1153  return false;
1154  }
1155 
1156  for (i = 0; i < variables.Size(); i++)
1157  {
1158  MHUnion *pValue = pEntry->m_Data.GetAt(i);
1159  MHLOG(MHLogNotifications, QString("Load Persistent(%1) #%2=%3")
1160  .arg(csFile).arg(i).arg(pValue->Printable()) );
1161  FindObject(*(variables.GetAt(i)))->SetVariableValue(*pValue);
1162  }
1163  }
1164 
1165  else // Get the data from the variables into the store.
1166  {
1167  // Remove any existing data.
1168  while (pEntry->m_Data.Size() != 0)
1169  {
1170  pEntry->m_Data.RemoveAt(0);
1171  }
1172 
1173  // Set the store to the values.
1174  for (i = 0; i < variables.Size(); i++)
1175  {
1176  auto *pValue = new MHUnion;
1177  pEntry->m_Data.Append(pValue);
1178  FindObject(*(variables.GetAt(i)))->GetVariableValue(*pValue, this);
1179  MHLOG(MHLogNotifications, QString("Store Persistent(%1) %2=>#%3")
1180  .arg(csFile).arg(pValue->Printable()).arg(i) );
1181  }
1182  }
1183 
1184  return true;
1185 }
1186 
1187 // Find out what we support.
1189 {
1190  QString csFeat = QString::fromUtf8((const char *)feature.Bytes(), feature.Size());
1191  QStringList strings = csFeat.split(QRegExp("[\\(\\,\\)]"));
1192 
1193  MHLOG(MHLogNotifications, "NOTE GetEngineSupport " + csFeat);
1194 
1195  if (strings[0] == "ApplicationStacking" || strings[0] == "ASt")
1196  {
1197  return true;
1198  }
1199 
1200  // We're required to support cloning for Text, Bitmap and Rectangle.
1201  if (strings[0] == "Cloning" || strings[0] == "Clo")
1202  {
1203  return true;
1204  }
1205 
1206  if (strings[0] == "SceneCoordinateSystem" || strings[0] == "SCS")
1207  {
1208  return strings.count() >= 3 && strings[1] == "720" && strings[2] == "576";
1209 
1210  // I've also seen SceneCoordinateSystem(1,1)
1211  }
1212 
1213  if (strings[0] == "MultipleAudioStreams" || strings[0] == "MAS")
1214  {
1215  return strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1");
1216  }
1217 
1218  if (strings[0] == "MultipleVideoStreams" || strings[0] == "MVS")
1219  {
1220  return strings.count() >= 2 && (strings[1] == "0" || strings[1] == "1");
1221  }
1222 
1223  // We're supposed to return true for all values of N
1224  if (strings[0] == "OverlappingVisibles" || strings[0] == "OvV")
1225  {
1226  return true;
1227  }
1228 
1229  if (strings[0] == "SceneAspectRatio" || strings[0] == "SAR")
1230  {
1231  if (strings.count() < 3)
1232  {
1233  return false;
1234  }
1235  return (strings[1] == "4" && strings[2] == "3") || (strings[1] == "16" && strings[2] == "9");
1236  }
1237 
1238  // We're supposed to support these at least. May also support(10,1440,1152)
1239  if (strings[0] == "VideoScaling" || strings[0] == "VSc")
1240  {
1241  if (strings.count() < 4 || strings[1] != "10")
1242  {
1243  return false;
1244  }
1245  return (strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288");
1246  }
1247 
1248  if (strings[0] == "BitmapScaling" || strings[0] == "BSc")
1249  {
1250  if (strings.count() < 4 || strings[1] != "2")
1251  {
1252  return false;
1253  }
1254  return (strings[2] == "720" && strings[3] == "576") || (strings[2] == "360" && strings[3] == "288");
1255  }
1256 
1257  // I think we only support the video fully on screen
1258  if (strings[0] == "VideoDecodeOffset" || strings[0] == "VDO")
1259  {
1260  return strings.count() >= 3 && strings[1] == "10" && strings[1] == "0";
1261  }
1262 
1263  // We support bitmaps that are partially off screen (don't we?)
1264  if (strings[0] == "BitmapDecodeOffset" || strings[0] == "BDO")
1265  {
1266  if (strings.count() >= 3 && strings[1] == "2" && (strings[2] == "0" || strings[2] == "1"))
1267  {
1268  return true;
1269  }
1270  if (strings.count() >= 2 && (strings[1] == "4" || strings[1] == "6"))
1271  {
1272  return true;
1273  }
1274  return false;
1275  }
1276 
1277  if (strings[0] == "UKEngineProfile" || strings[0] == "UniversalEngineProfile" || strings[0] == "UEP")
1278  {
1279  if (strings.count() < 2)
1280  {
1281  return false;
1282  }
1283 
1284  if (strings[1] == MHEGEngineProviderIdString)
1285  {
1286  return true;
1287  }
1288 
1289  if (strings[1] == m_Context->GetReceiverId())
1290  {
1291  return true;
1292  }
1293 
1294  if (strings[1] == m_Context->GetDSMCCId())
1295  {
1296  return true;
1297  }
1298 
1299  // The UK profile 1.06 seems a bit confused on this point. It is not clear whether
1300  // we are supposed to return true for UKEngineProfile(2) or not.
1301  if (strings[1] == "2")
1302  return true;
1303  if (strings[1] == "1")
1304  return true;
1305  // 'The Space' on Freeview checks this...
1306  if (strings[1] == "PANT11001")
1307  return true;
1308  // Irish DTT expects "1285". From ETSI ES 202 184: UEP(1285) means the receiver has been verified as fully conformant.
1309  if (strings[1] == "1285")
1310  return true;
1311 
1312  return false;
1313  }
1314 
1315  // InteractionChannelExtension.
1316  if (strings[0] == "ICProfile" || strings[0] == "ICP") {
1317  if (strings.count() < 2) return false;
1318  if (strings[1] == "0")
1319  return true; // InteractionChannelExtension.
1320  if (strings[1] == "1")
1321  return true; // ICStreamingExtension. This is a deliberate lie
1322  return false;
1323  }
1324 
1325  if (strings[0] == "HDExtension" || strings[0] == "HDE") {
1326  if (strings.count() < 2) return false;
1327  if (strings[1] == "0")
1328  return false; // HDVideoExtension.
1329  if (strings[1] == "1")
1330  return false; // HDGraphicsPlaneExtension
1331  return false;
1332  }
1333  if (strings[0] == "HDGraphicsPlaneExtension" || strings[0] == "HDG") {
1334  if (strings.count() < 2) return false;
1335  // true if HDGraphicsPlaneExtension
1336  return strings[1] == "0";
1337  }
1338 
1339  // Otherwise return false.
1340  return false;
1341 }
1342 
1343 // Get the various defaults. These are extracted from the current app or the (UK) MHEG defaults.
1345 {
1346  MHApplication *pApp = CurrentApp();
1347 
1348  if (pApp && pApp->m_nCharSet > 0)
1349  {
1350  return pApp->m_nCharSet;
1351  }
1352  return 10; // UK MHEG default.
1353 }
1354 
1356 {
1357  MHApplication *pApp = CurrentApp();
1358 
1359  if (pApp && pApp->m_BGColour.IsSet())
1360  {
1361  colour.Copy(pApp->m_BGColour);
1362  }
1363  else
1364  {
1365  colour.SetFromString("\000\000\000\377", 4); // '=00=00=00=FF' Default - transparent
1366  }
1367 }
1368 
1370 {
1371  MHApplication *pApp = CurrentApp();
1372 
1373  if (pApp && pApp->m_TextColour.IsSet())
1374  {
1375  colour.Copy(pApp->m_TextColour);
1376  }
1377  else
1378  {
1379  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1380  }
1381 }
1382 
1384 {
1385  MHApplication *pApp = CurrentApp();
1386 
1387  if (pApp && pApp->m_ButtonRefColour.IsSet())
1388  {
1389  colour.Copy(pApp->m_ButtonRefColour);
1390  }
1391  else
1392  {
1393  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' ??? Not specified in UK MHEG
1394  }
1395 }
1396 
1398 {
1399  MHApplication *pApp = CurrentApp();
1400 
1401  if (pApp && pApp->m_HighlightRefColour.IsSet())
1402  {
1403  colour.Copy(pApp->m_HighlightRefColour);
1404  }
1405  else
1406  {
1407  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1408  }
1409 }
1410 
1412 {
1413  MHApplication *pApp = CurrentApp();
1414 
1415  if (pApp && pApp->m_SliderRefColour.IsSet())
1416  {
1417  colour.Copy(pApp->m_SliderRefColour);
1418  }
1419  else
1420  {
1421  colour.SetFromString("\377\377\377\000", 4); // '=FF=FF=FF=00' UK MHEG Default - white
1422  }
1423 }
1424 
1426 {
1427  MHApplication *pApp = CurrentApp();
1428 
1429  if (pApp && pApp->m_nTextCHook > 0)
1430  {
1431  return pApp->m_nTextCHook;
1432  }
1433  return 10; // UK MHEG default.
1434 }
1435 
1437 {
1438  MHApplication *pApp = CurrentApp();
1439 
1440  if (pApp && pApp->m_nStrCHook > 0)
1441  {
1442  return pApp->m_nStrCHook;
1443  }
1444  return 10; // UK MHEG default.
1445 }
1446 
1448 {
1449  MHApplication *pApp = CurrentApp();
1450 
1451  if (pApp && pApp->m_nBitmapCHook > 0)
1452  {
1453  return pApp->m_nBitmapCHook;
1454  }
1455  return 4; // UK MHEG default - PNG bitmap
1456 }
1457 
1459 {
1460  MHApplication *pApp = CurrentApp();
1461 
1462  if (pApp && pApp->m_FontAttrs.Size() > 0)
1463  {
1464  str.Copy(pApp->m_FontAttrs);
1465  }
1466  else
1467  {
1468  str.Copy("plain.24.24.0"); // TODO: Check this.
1469  }
1470 }
1471 
1472 // An identifier string required by the UK profile. The "manufacturer" is GNU.
1473 const char *MHEngine::MHEGEngineProviderIdString = "MHGGNU001";
1474 
1475 // Define the logging function and settings
1477 
1478 FILE *__mhlogStream = nullptr;
1479 
1480 // The MHEG engine calls this when it needs to log something.
1481 void __mhlog(const QString& logtext)
1482 {
1483  QByteArray tmp = logtext.toLatin1();
1484  fprintf(__mhlogStream, "[freemheg] %s\n", tmp.constData());
1485 }
1486 
1487 // Called from the user of the library to set the logging.
1488 void MHSetLogging(FILE *logStream, unsigned int logLevel)
1489 {
1490  __mhlogStream = logStream;
1492 }
static void Failure(const char *p)
Definition: ParseNode.cpp:43
void GetDefaultTextColour(MHColour &colour)
Definition: Engine.cpp:1369
bool m_fInTransition
Definition: Engine.h:201
void Deactivation(MHEngine *engine) override
Definition: Groups.cpp:305
int GetDefaultCharSet()
Definition: Engine.cpp:1344
void AddToDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:734
#define MHERROR(__text)
Definition: Logging.h:42
void RunActions()
Definition: Engine.cpp:614
void GetDefaultButtonRefColour(MHColour &colour)
Definition: Engine.cpp:1383
MHColour m_BGColour
Definition: Groups.h:132
virtual void SetVariableValue(const MHUnion &)
Definition: Root.h:108
void RemoveFromDisplayStack(MHVisible *pVis)
Definition: Engine.cpp:746
QList< MHExternContent * > m_ExternContentTable
Definition: Engine.h:196
BASE GetAt(int i) const
Definition: BaseClasses.h:48
MHOwnPtrSequence< MHPSEntry > m_PersistentStore
Definition: Engine.h:199
int GetDefaultStreamCHook()
Definition: Engine.cpp:1436
bool IsSet() const
Definition: BaseClasses.h:142
virtual void GetVariableValue(MHUnion &, MHEngine *)
Definition: Root.h:106
~MHEngine() override
Definition: Engine.cpp:59
int m_nBitmapCHook
Definition: Groups.h:136
MHColour m_TextColour
Definition: Groups.h:132
MHScene * m_pCurrentScene
Definition: Groups.h:149
void PutBefore(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:790
MHOctetString m_FontAttrs
Definition: Groups.h:139
virtual QRegion GetVisibleArea()
Definition: Visible.cpp:197
void __mhlog(const QString &logtext)
Definition: Engine.cpp:1481
int CheckTimers(MHEngine *engine)
Definition: Groups.cpp:389
void GetDefaultBGColour(MHColour &colour)
Definition: Engine.cpp:1355
MHOwnPtrSequence< MHIngredient > m_Items
Definition: Groups.h:70
QString Printable() const
void GetDefaultSliderRefColour(MHColour &colour)
Definition: Engine.cpp:1411
virtual void Deactivation(MHEngine *engine)
Definition: Root.cpp:85
EProtocol
Definition: Engine.cpp:253
void RequestExternalContent(MHIngredient *pRequester)
Definition: Engine.cpp:969
void InsertAt(BASE b, int n)
Definition: BaseClasses.h:52
void AddLink(MHLink *pLink)
Definition: Engine.cpp:713
const unsigned char * Bytes() const
Definition: BaseClasses.h:123
#define C_SCENE
Definition: ASN1Codes.h:34
MHScene * CurrentScene()
Definition: Engine.h:180
bool Launch(const MHObjectRef &target, bool fIsSpawn=false)
Definition: Engine.cpp:274
void RemoveLink(MHLink *pLink)
Definition: Engine.cpp:718
int m_nCharSet
Definition: Groups.h:131
void Copy(const MHColour &col)
static guint32 * tmp
Definition: goom_core.c:35
#define C_APPLICATION
Definition: ASN1Codes.h:33
static EProtocol PathProtocol(const QString &csPath)
Definition: Engine.cpp:254
MHApplication * CurrentApp()
Definition: Engine.h:175
QTime m_time
Definition: Engine.h:66
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Groups.cpp:48
virtual void PrintMe(FILE *fd, int nTabs) const
Definition: BaseActions.cpp:37
QString m_FileName
Definition: Engine.h:64
virtual void ContentArrived(const unsigned char *, int, MHEngine *)
Definition: Ingredients.h:62
int FindOnStack(const MHRoot *pVis)
Definition: Groups.cpp:709
void StreamStarted(MHStream *stream, bool bStarted) override
Definition: Engine.cpp:963
int m_nLockCount
Definition: Groups.h:143
void Redraw(const QRegion &region)
Definition: Engine.cpp:899
int GetDefaultBitmapCHook()
Definition: Engine.cpp:1447
int GetDefaultTextCHook()
Definition: Engine.cpp:1425
virtual void RequireRedraw(const QRegion &region)=0
virtual const char * GetDSMCCId(void)=0
virtual bool CheckStop(void)=0
void SetFromString(const char *str, int nLen)
Definition: freemheg.h:48
MHRoot * FindByObjectNo(int n) override
Definition: Groups.cpp:330
void GetDefaultHighlightRefColour(MHColour &colour)
Definition: Engine.cpp:1397
void Copy(const MHOctetString &str)
QStack< MHElemAction * > m_ActionStack
Definition: Engine.h:185
MHInteractible * m_Interacting
Definition: Engine.h:210
int Size() const
Definition: BaseClasses.h:118
bool IsShared() override
Definition: Ingredients.h:44
void RemoveAt(int i)
Definition: BaseClasses.h:65
void Preparation(MHEngine *engine) override
Definition: Groups.cpp:258
bool m_fIsApp
Definition: Groups.h:71
QString Printable() const
FILE * __mhlogStream
Definition: Engine.cpp:1478
void CancelExternalContentRequest(MHIngredient *pRequester)
Definition: Engine.cpp:1028
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:93
int m_nStrCHook
Definition: Groups.h:135
bool LoadStorePersistent(bool fIsLoad, const MHOctetString &fileName, const MHSequence< MHObjectRef * > &variables)
Definition: Engine.cpp:1110
QRegion m_redrawRegion
Definition: Engine.h:171
virtual void DrawBackground(const QRegion &reg)=0
void CheckContentRequests()
Definition: Engine.cpp:1049
MHGroup * ParseProgram(QByteArray &text)
Definition: Engine.cpp:195
int m_nTextCHook
Definition: Groups.h:133
virtual bool GetCarouselData(QString objectPath, QByteArray &result)=0
void PutBehind(const MHRoot *pVis, const MHRoot *pRef)
Definition: Engine.cpp:821
void CheckLinks(const MHObjectRef &sourceRef, enum EventType ev, const MHUnion &un)
Definition: Engine.cpp:706
Definition: Root.h:43
virtual void Display(MHEngine *)=0
void TransitionToScene(const MHObjectRef &target)
Definition: Engine.cpp:419
MHObjectRef m_ObjectReference
Definition: Root.h:247
Definition: Groups.h:86
int FILE
Definition: mythburn.py:110
enum EventType m_eventType
Definition: Engine.h:47
virtual QRegion GetOpaqueArea()
Definition: Visible.h:65
int __mhlogoptions
Definition: Engine.cpp:1476
MHUnion m_eventData
Definition: Engine.h:48
MHContext * m_Context
Definition: Engine.h:207
MHColour m_ButtonRefColour
Definition: Groups.h:132
MHEG * MHCreateEngine(MHContext *context)
Definition: Engine.cpp:43
bool IsSet() const
Definition: BaseClasses.h:182
void GetDefaultFontAttrs(MHOctetString &str)
Definition: Engine.cpp:1458
MHRoot * m_pEventSource
Definition: Engine.h:46
void DrawDisplay(QRegion toDraw) override
Definition: Engine.cpp:886
void Destruction(MHEngine *engine) override
Definition: Groups.cpp:319
QStack< MHApplication * > m_ApplicationStack
Definition: Engine.h:174
void UnlockScreen()
Definition: Engine.cpp:905
LogLevel_t logLevel
Definition: logging.cpp:95
MHRoot * FindObject(const MHObjectRef &oRef, bool failOnNotFound=true)
Definition: Engine.cpp:574
QString GetPathName(const MHOctetString &str)
Definition: Engine.cpp:524
virtual void KeyEvent(MHEngine *, int)
Definition: Visible.h:151
virtual bool CheckCarouselObject(QString objectPath)=0
#define MHLOG(__level, __text)
Definition: Logging.h:36
Definition: Groups.h:45
#define CONTENT_CHECK_TIME
Definition: Engine.cpp:78
MHOctetString m_ContentRef
Definition: BaseClasses.h:187
void BringToFront(const MHRoot *pVis)
Definition: Engine.cpp:760
MHOctetString m_GroupId
Definition: BaseClasses.h:168
void DrawRegion(const QRegion &toDraw, int nStackPos)
Definition: Engine.cpp:852
void Activation(MHEngine *engine) override
Definition: Groups.cpp:691
QQueue< MHAsynchEvent * > m_EventQueue
Definition: Engine.h:189
void Quit()
Definition: Engine.cpp:378
MHSequence< MHVisible * > m_DisplayStack
Definition: Groups.h:146
int GetTagNo()
Definition: ParseNode.cpp:49
virtual void SetInputRegister(int nReg)=0
MHColour m_HighlightRefColour
Definition: Groups.h:132
int RunAll(void) override
Definition: Engine.cpp:81
void SetInputRegister(int nReg)
Definition: Engine.cpp:518
void PrintMe(FILE *fd, int nTabs) const override
Definition: Groups.cpp:217
EventType
Definition: Root.h:33
MHEngine(MHContext *context)
Definition: Engine.cpp:48
void Append(BASE b)
Definition: BaseClasses.h:63
void MHSetLogging(FILE *logStream, unsigned int logLevel)
Definition: Engine.cpp:1488
bool m_fRestarting
Definition: Groups.h:150
int Size() const
Definition: BaseClasses.h:46
void SendToBack(const MHRoot *pVis)
Definition: Engine.cpp:775
static const char * MHEGEngineProviderIdString
Definition: Engine.h:157
void AddActions(const MHActionSequence &actions)
Definition: Engine.cpp:724
QList< MHLink * > m_LinkTable
Definition: Engine.h:192
void EngineEvent(int nCode) override
Definition: Engine.cpp:955
MHOctetString m_FileName
Definition: Engine.h:57
MHContentRef m_ContentRef
Definition: Ingredients.h:78
bool m_fBooting
Definition: Engine.h:208
virtual const char * GetReceiverId(void)=0
QString m_Path
Definition: Groups.h:151
MHIngredient * m_pRequester
Definition: Engine.h:65
void Activation(MHEngine *engine) override
Definition: Groups.cpp:275
bool GetEngineSupport(const MHOctetString &feature)
Definition: Engine.cpp:1188
MHColour m_SliderRefColour
Definition: Groups.h:132
void GenerateUserAction(int nCode) override
Definition: Engine.cpp:915
virtual void Perform(MHEngine *engine)=0